diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 880ee195a1..f3bd0a8e20 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,88 @@ 2002-12-01 13:30 UTC+0100 Foo Bar */ +2008-03-05 19:10 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/contrib/hbct/screen2.c + ! fixed possible vary bad bug (memory buffer overflow) in SCREENSTR() + + * harbour/source/rtl/hbffind.c + ! fixed possible GPF in some *nixes + + * harbour/source/vm/classes.c + ! do not execute the same destructor inherited from different parent + classes more then once + + * harbour/source/rtl/transfrm.c + ! fixed bug with '9' used as stop condition of function pattern + this character cannot be stripped, f.e.: + ? transform( "abc", "@_99*" ) + ! fixed bug with '*' or '$' used with @), f.e.: + ? transform( -12345, "@) $999999" ) + ! fixed replacing '.' with ',' when @E is used without picture part, f.e.: + ? transform( 123.45, "@E" ) + ! fixed ',' conversions + ? transform( 12.34,"@E ab,cd.ef9,9.99,.--" ) + ! fixed bug with picture starting with ".", f.e.: + ? transform( 0.3456, ".999" ) + ! fixed "@(" and "@)" conversions, f.e.: + ? transform( -12345, "@) 1999*999" ) + ! fixed late oveflow detection in "@(" and "@)", f.e.: + ? transtest( -12345, "@( 6798^999" ) + ! fixed "@E" conversion for dates to keep user delimiters set in + _SET_DATEFORMAT, f.e.: + set( _SET_DATEFORMAT, "mm:dd:yyyy" ); ? transform( date(), "@E" ) + set( _SET_DATEFORMAT, "yyyydd" ); ? transform( date(), "@E" ) + Please note that Harbour is not strictly Clipper compatible here + because it respects _SET_DATEFORMAT set by user. + ! fixed 64bit integer conversion by eliminating conversion to + 'double' f.e.: + ? transform( 1234567890123456789, "99999999999999999999" ) + ? transform( -1234567890123456789, "99999999999999999999" ) + ! some other fixes, see regression test transtst.prg + % speed improvement in numeric conversions + + + harbour/tests/transtst.prg + + added regression test for transform function + + * harbour/utils/hbtest/rt_trans.prg + * disabled transform() tests for "@E" and result smaller then 5 bytes + CA-Cl*pper do not check result size and always exchanges + bytes 1-2 with bytes 4-5 for @E conversion. It's buffer overflow + bug and I do not want to replicate it inside our transform + implementation. It also causes that the results for for strings + smaller then 5 bytes behaves randomly. + In fact precise tests can show that it's not random behavior + but CA-Cl*pper uses static buffer for result and when current one + is smaller then 5 bytes then first two bytes are replaced with + 4-5 bytes from previous result which was length enough, f.e.: + ? transform( "0123456789", "" ) + ? transform( "AB", "@E" ) + ? transform( "ab", "@E" ) + Replicating exact CA-Cl*pper behavior it's trivial (it will be enough + to use static buffer two and not check the size of current result) but + IMHO it's bug. + + * harbour/source/rtl/round.c + * added strictly Clipper compatible code covered by HB_C52_STRICT + and comment about possible difference in Harbour. + + * harbour/include/hbgtinfo.ch + * harbour/source/rtl/hbgtcore.c + * harbour/source/rtl/gtxwc/gtxwc.c + * harbour/source/rtl/gtsln/gtsln.c + * harbour/source/rtl/gttrm/gttrm.c + * harbour/source/rtl/gtwvt/gtwvt.c + + added HB_GTI_ISUNICODE - it returns logical value with information + about Unicode mode in active GT driver - it's necessary for proper + CP initialization in some GTDs which can work in both mode depending + on client side settings + + * harbour/source/rtl/gttrm/gttrm.c + * improved UTF-8 detection + * added automatic PuTTY detection + * improved PuTTY and some xterm key handling + * added some missing RXVT keys + 2008-02-25 00:08 UTC-0600 Teo Fonrouge (teo/at/windtelsoft/dot/com) * make_vc.mak ! Fixed small typo diff --git a/harbour/contrib/hbct/screen2.c b/harbour/contrib/hbct/screen2.c index c2607101b2..147f867c45 100644 --- a/harbour/contrib/hbct/screen2.c +++ b/harbour/contrib/hbct/screen2.c @@ -344,9 +344,9 @@ HB_FUNC( SCREENSTR ) *szText++ = ( char ) usChar; *szText++ = ( char ) bColor; } - while( ++sC <= sMaxCol && --ulCount ); + while( --ulCount && ++sC <= sMaxCol ); } - while( ++sRow <= sMaxRow && ulCount ); + while( ulCount && ++sRow <= sMaxRow ); hb_retclen_buffer( pBuffer, ulSize ); } diff --git a/harbour/include/hbgtinfo.ch b/harbour/include/hbgtinfo.ch index b57eed906e..aaf8ebb7cb 100644 --- a/harbour/include/hbgtinfo.ch +++ b/harbour/include/hbgtinfo.ch @@ -116,6 +116,8 @@ #define HB_GTI_ADDKEYMAP 45 /* add key escape sequences */ #define HB_GTI_DELKEYMAP 46 /* del key escape sequences */ +#define HB_GTI_ISUNICODE 47 /* is Unicode input/output enabled? */ + /* Font weights */ #define HB_GTI_FONTW_THIN 1 #define HB_GTI_FONTW_NORMAL 2 @@ -192,6 +194,7 @@ #define GTI_NEWWIN HB_GTI_NEWWIN #define GTI_ADDKEYMAP HB_GTI_ADDKEYMAP #define GTI_DELKEYMAP HB_GTI_DELKEYMAP +#define GTI_ISUNICODE HB_GTI_ISUNICODE /* Font weights */ #define GTI_FONTW_THIN HB_GTI_FONTW_THIN diff --git a/harbour/source/rtl/gtsln/gtsln.c b/harbour/source/rtl/gtsln/gtsln.c index 9076585a2a..cacfe44e56 100644 --- a/harbour/source/rtl/gtsln/gtsln.c +++ b/harbour/source/rtl/gtsln/gtsln.c @@ -906,6 +906,10 @@ static BOOL hb_gt_sln_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) pInfo->pResult = hb_itemPutL( pInfo->pResult, TRUE ); break; + case HB_GTI_ISUNICODE: + pInfo->pResult = hb_itemPutL( pInfo->pResult, hb_sln_Is_Unicode ); + break; + case HB_GTI_ESCDELAY: pInfo->pResult = hb_itemPutNI( pInfo->pResult, hb_sln_escDelay ); if( hb_itemType( pInfo->pNewVal ) & HB_IT_NUMERIC ) diff --git a/harbour/source/rtl/gttrm/gttrm.c b/harbour/source/rtl/gttrm/gttrm.c index 2453cc5217..b1ffa47139 100644 --- a/harbour/source/rtl/gttrm/gttrm.c +++ b/harbour/source/rtl/gttrm/gttrm.c @@ -119,6 +119,7 @@ static HB_GT_FUNCS SuperTable; #define TERM_ANSI 1 #define TERM_LINUX 2 #define TERM_XTERM 3 +#define TERM_PUTTY 4 #define NO_STDKEYS 96 #define NO_EXTDKEYS 30 @@ -336,6 +337,7 @@ typedef struct _HB_GTTRM BYTE * pOutBuf; int terminal_type; + int terminal_ext; #if defined( OS_UNIX_COMPATIBLE ) struct termios saved_TIO, curr_TIO; @@ -374,7 +376,7 @@ typedef struct _HB_GTTRM void (* Init) ( HB_GTTRM_PTR ); void (* Exit) ( HB_GTTRM_PTR ); void (* SetTermMode) ( HB_GTTRM_PTR, int ); - BOOL (* GetCursorPos) ( HB_GTTRM_PTR, int *, int * ); + BOOL (* GetCursorPos) ( HB_GTTRM_PTR, int *, int *, const char * ); void (* SetCursorPos) ( HB_GTTRM_PTR, int , int ); void (* SetCursorStyle) ( HB_GTTRM_PTR, int ); void (* SetAttributes) ( HB_GTTRM_PTR, int ); @@ -1717,9 +1719,10 @@ static void hb_gt_trm_AnsiSetTermMode( PHB_GTTRM pTerm, int iAM ) } } -static BOOL hb_gt_trm_AnsiGetCursorPos( PHB_GTTRM pTerm, int * iRow, int * iCol ) +static BOOL hb_gt_trm_AnsiGetCursorPos( PHB_GTTRM pTerm, int * iRow, int * iCol, + const char * szPost ) { - HB_TRACE(HB_TR_DEBUG, ("hb_gt_trm_AnsiGetCursorPos(%p,%p,%p)", pTerm, iRow, iCol)); + HB_TRACE(HB_TR_DEBUG, ("hb_gt_trm_AnsiGetCursorPos(%p,%p,%p,%p)", pTerm, iRow, iCol, szPost)); if( pTerm->fPosAnswer ) { @@ -1727,6 +1730,8 @@ static BOOL hb_gt_trm_AnsiGetCursorPos( PHB_GTTRM pTerm, int * iRow, int * iCol int i, n, y, x; hb_gt_trm_termOut( pTerm, ( BYTE * ) "\x1B[6n", 4 ); + if( szPost ) + hb_gt_trm_termOut( pTerm, ( BYTE * ) szPost, strlen( szPost ) ); hb_gt_trm_termFlush( pTerm ); *iRow = *iCol = -1; @@ -1751,7 +1756,15 @@ static BOOL hb_gt_trm_AnsiGetCursorPos( PHB_GTTRM pTerm, int * iRow, int * iCol if( n == 0 ) { while( i > 0 && rdbuf[0] != '\033' ) - memmove( rdbuf, rdbuf + 1, i-- ); + { + if( szPost && i >= 5 && hb_strnicmp( rdbuf, "PuTTY", 5 ) == 0 ) + { + pTerm->terminal_ext |= TERM_PUTTY; + memmove( rdbuf, rdbuf + 5, i -= 5 ); + } + else + memmove( rdbuf, rdbuf + 1, i-- ); + } } n += i; if( n >= 6 ) @@ -2042,11 +2055,8 @@ static BOOL hb_trm_isUTF8( PHB_GTTRM pTerm ) int iRow = 0, iCol = 0; BOOL fSize; - hb_gt_trm_termOut( pTerm, ( BYTE * ) "\r\303\255", 3 ); - hb_gt_trm_termFlush( pTerm ); - fSize = pTerm->GetCursorPos( pTerm, &iRow, &iCol ); - hb_gt_trm_termOut( pTerm, ( BYTE * ) "\r \r", 4 ); - hb_gt_trm_termFlush( pTerm ); + hb_gt_trm_termOut( pTerm, ( BYTE * ) "\005\r\303\255", 4 ); + fSize = pTerm->GetCursorPos( pTerm, &iRow, &iCol, "\r \r" ); pTerm->iCol = 0; if( fSize ) return iCol == 1; @@ -2324,6 +2334,13 @@ static void init_keys( PHB_GTTRM pTerm ) { 0, NULL } }; + static const keySeq rxvtKeySeq[] = { + + { EXKEY_HOME, "\033[H" }, + { EXKEY_END, "\033Ow" }, + + { 0, NULL } }; + static const keySeq xtermModKeySeq[] = { { EXKEY_F1 |KEY_CTRLMASK, "\033O5P" }, @@ -2401,6 +2418,8 @@ static void init_keys( PHB_GTTRM pTerm ) { EXKEY_PGUP |KEY_CTRLMASK|KEY_ALTMASK, "\033[5;2~" }, { EXKEY_PGDN |KEY_CTRLMASK|KEY_ALTMASK, "\033[6;2~" }, + { EXKEY_BS |KEY_ALTMASK, "\033\010" }, + { 0, NULL } }; static const keySeq xtermFnKeySeq[] = { @@ -2459,6 +2478,8 @@ static void init_keys( PHB_GTTRM pTerm ) /* Konsole */ { EXKEY_ENTER |KEY_CTRLMASK|KEY_ALTMASK, "\033OM" }, + { EXKEY_END, "\033Ow" }, /* rxvt */ + /* gnome-terminal */ { EXKEY_END, "\033OF" }, /* kend */ { EXKEY_HOME, "\033OH" }, /* khome */ @@ -2623,6 +2644,8 @@ static void init_keys( PHB_GTTRM pTerm ) addKeyTab( pTerm, xtermFnKeySeq ); addKeyTab( pTerm, xtermModKeySeq ); addKeyTab( pTerm, puttyKeySeq ); + /* if( pTerm->terminal_ext & TERM_PUTTY ) for PuTTY */ + addKeyTab( pTerm, rxvtKeySeq ); } else if( pTerm->terminal_type == TERM_ANSI ) { @@ -2716,7 +2739,7 @@ static void hb_gt_trm_SetTerm( PHB_GTTRM pTerm ) { static const char * szAcsc = "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; static const char * szExtAcsc = "+\020,\021-\030.\0310\333`\004a\261f\370g\361h\260i\316j\331k\277l\332m\300n\305o~p\304q\304r\304s_t\303u\264v\301w\302x\263y\363z\362{\343|\330}\234~\376"; - char * szTerm; + const char * szTerm; HB_TRACE(HB_TR_DEBUG, ("hb_gt_trm_SetTerm(%p)", pTerm)); @@ -2756,7 +2779,8 @@ static void hb_gt_trm_SetTerm( PHB_GTTRM pTerm ) pTerm->szAcsc = szExtAcsc; pTerm->terminal_type = TERM_LINUX; } - else if( strstr( szTerm, "xterm" ) != NULL || + else if( ( pTerm->terminal_ext & TERM_PUTTY ) || + strstr( szTerm, "xterm" ) != NULL || strncmp( szTerm, "rxvt", 4 ) == 0 || strcmp( szTerm, "putty" ) == 0 || strncmp( szTerm, "screen", 6 ) == 0 ) @@ -2892,15 +2916,15 @@ static void hb_gt_trm_Init( PHB_GT pGT, FHANDLE hFilenoStdin, FHANDLE hFilenoStd HB_GTSELF_SETFLAG( pGT, HB_GTI_COMPATBUFFER, FALSE ); HB_GTSELF_SETFLAG( pGT, HB_GTI_STDOUTCON, pTerm->fStdoutTTY ); HB_GTSELF_SETFLAG( pGT, HB_GTI_STDERRCON, pTerm->fStderrTTY ); - HB_GTSELF_SETBLINK( pGT, TRUE ); pTerm->Init( pTerm ); pTerm->SetTermMode( pTerm, 0 ); - if( pTerm->GetCursorPos( pTerm, &pTerm->iRow, &pTerm->iCol ) ) + if( pTerm->GetCursorPos( pTerm, &pTerm->iRow, &pTerm->iCol, NULL ) ) HB_GTSELF_SETPOS( pGT, pTerm->iRow, pTerm->iCol ); pTerm->fUTF8 = hb_trm_isUTF8( pTerm ); hb_gt_trm_SetKeyTrans( pTerm, NULL, NULL ); hb_gt_trm_SetDispTrans( pTerm, NULL, NULL, 0 ); + HB_GTSELF_SETBLINK( pGT, TRUE ); if( pTerm->fOutTTY ) HB_GTSELF_SEMICOLD( pGT ); } @@ -3085,9 +3109,9 @@ static char * hb_gt_trm_Version( PHB_GT pGT, int iType ) HB_SYMBOL_UNUSED( pGT ); if( iType == 0 ) - return HB_GT_DRVNAME( HB_GT_NAME ); + return ( char * ) HB_GT_DRVNAME( HB_GT_NAME ); - return "Harbour terminal driver"; + return ( char * ) "Harbour terminal driver"; } static BOOL hb_gt_trm_Suspend( PHB_GT pGT ) @@ -3182,10 +3206,28 @@ static void hb_gt_trm_SetBlink( PHB_GT pGT, BOOL fBlink ) HB_TRACE( HB_TR_DEBUG, ( "hb_gt_trm_SetBlink(%p,%d)", pGT, ( int ) fBlink ) ); pTerm = HB_GTTRM_GET( pGT ); - if( fBlink ) + +#if 0 + /* This is not portable extension - temporary disabled */ + if( pTerm->terminal_ext & TERM_PUTTY ) + { + static const char * szBlinkOff = "\033[=0E"; /* disable blinking, highlight bkg */ + static const char * szBlinkOn = "\033[=1E"; /* enable blinking */ + + const char * szBlink = fBlink ? szBlinkOn : szBlinkOff; + pTerm->iAttrMask |= 0x0080; + hb_gt_trm_termOut( pTerm, ( BYTE * ) szBlink, strlen( szBlink ) ); + hb_gt_trm_termFlush( pTerm ); + } else - pTerm->iAttrMask &= ~0x0080; +#endif + { + if( fBlink ) + pTerm->iAttrMask |= 0x0080; + else + pTerm->iAttrMask &= ~0x0080; + } HB_GTSUPER_SETBLINK( pGT, fBlink ); } @@ -3380,6 +3422,10 @@ static BOOL hb_gt_trm_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) pInfo->pResult = hb_itemPutL( pInfo->pResult, TRUE ); break; + case HB_GTI_ISUNICODE: + pInfo->pResult = hb_itemPutL( pInfo->pResult, pTerm->fUTF8 ); + break; + case HB_GTI_ESCDELAY: pInfo->pResult = hb_itemPutNI( pInfo->pResult, pTerm->esc_delay ); if( hb_itemType( pInfo->pNewVal ) & HB_IT_NUMERIC ) @@ -3441,7 +3487,7 @@ static BOOL hb_gt_FuncInit( PHB_GT_FUNCS pFuncTable ) /* ********************************************************************** */ -static const HB_GT_INIT gtInit = { HB_GT_DRVNAME( HB_GT_NAME ), +static const HB_GT_INIT gtInit = { ( char * ) HB_GT_DRVNAME( HB_GT_NAME ), hb_gt_FuncInit, HB_GTSUPER, HB_GTID_PTR }; diff --git a/harbour/source/rtl/gtwvt/gtwvt.c b/harbour/source/rtl/gtwvt/gtwvt.c index af06f9d9fd..2f6f7498d5 100644 --- a/harbour/source/rtl/gtwvt/gtwvt.c +++ b/harbour/source/rtl/gtwvt/gtwvt.c @@ -1486,6 +1486,14 @@ static BOOL hb_gt_wvt_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) pInfo->pResult = hb_itemPutL( pInfo->pResult, TRUE ); break; + case HB_GTI_ISUNICODE: +#if defined(UNICODE) + pInfo->pResult = hb_itemPutL( pInfo->pResult, TRUE ); +#else + pInfo->pResult = hb_itemPutL( pInfo->pResult, FALSE ); +#endif + break; + case HB_GTI_INPUTFD: pInfo->pResult = hb_itemPutNInt( pInfo->pResult, ( UINT_PTR ) GetStdHandle( STD_INPUT_HANDLE ) ); diff --git a/harbour/source/rtl/gtxwc/gtxwc.c b/harbour/source/rtl/gtxwc/gtxwc.c index ac028c96c0..c66baadd61 100644 --- a/harbour/source/rtl/gtxwc/gtxwc.c +++ b/harbour/source/rtl/gtxwc/gtxwc.c @@ -3678,6 +3678,10 @@ static BOOL hb_gt_xwc_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) pInfo->pResult = hb_itemPutL( pInfo->pResult, wnd->dpy != NULL ); break; + case HB_GTI_ISUNICODE: + pInfo->pResult = hb_itemPutL( pInfo->pResult, TRUE ); + break; + case HB_GTI_INPUTFD: pInfo->pResult = hb_itemPutNI( pInfo->pResult, ConnectionNumber( wnd->dpy ) ); break; diff --git a/harbour/source/rtl/hbffind.c b/harbour/source/rtl/hbffind.c index 938fded326..4e17bf3e70 100644 --- a/harbour/source/rtl/hbffind.c +++ b/harbour/source/rtl/hbffind.c @@ -724,6 +724,8 @@ static BOOL hb_fsFindNextLow( PHB_FFIND ffind ) #else { + int TODO; /* TODO: for given platform */ + /* HB_SYMBOL_UNUSED( ffind ); */ HB_SYMBOL_UNUSED( nYear ); @@ -763,14 +765,16 @@ static BOOL hb_fsFindNextLow( PHB_FFIND ffind ) HB_EXPORT PHB_FFIND hb_fsFindFirst( const char * pszFileMask, USHORT attrmask ) { - PHB_FFIND ffind = ( PHB_FFIND ) hb_xgrab( sizeof( HB_FFIND ) ); + PHB_FFIND ffind; + + ffind = ( PHB_FFIND ) hb_xgrab( sizeof( HB_FFIND ) ); + memset( ffind, 0, sizeof( HB_FFIND ) ); /* Allocate platform dependent file find info storage */ - ffind->info = ( void * ) hb_xgrab( sizeof( HB_FFIND_INFO ) ); + memset( ffind->info, 0, sizeof( HB_FFIND_INFO ) ); /* Store search parameters */ - ffind->pszFileMask = pszFileMask; ffind->attrmask = attrmask; ffind->bFirst = TRUE; @@ -849,6 +853,7 @@ HB_EXPORT void hb_fsFindClose( PHB_FFIND ffind ) #elif defined(HB_OS_UNIX) + if( info->dir != NULL ) { closedir( info->dir ); } @@ -857,6 +862,7 @@ HB_EXPORT void hb_fsFindClose( PHB_FFIND ffind ) { /* Intentionally do nothing */ + int TODO; /* TODO: for given platform */ HB_SYMBOL_UNUSED( info ); } diff --git a/harbour/source/rtl/hbgtcore.c b/harbour/source/rtl/hbgtcore.c index 64e6411727..758407477d 100644 --- a/harbour/source/rtl/hbgtcore.c +++ b/harbour/source/rtl/hbgtcore.c @@ -1424,6 +1424,7 @@ static BOOL hb_gt_def_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) case HB_GTI_KBDSUPPORT: case HB_GTI_ISCTWIN: case HB_GTI_ISMULTIWIN: + case HB_GTI_ISUNICODE: pInfo->pResult = hb_itemPutL( pInfo->pResult, FALSE ); break; diff --git a/harbour/source/rtl/round.c b/harbour/source/rtl/round.c index 091ab42303..97025d1dec 100644 --- a/harbour/source/rtl/round.c +++ b/harbour/source/rtl/round.c @@ -98,10 +98,18 @@ HB_FUNC( ROUND ) { int iDec = hb_parni( 2 ); +#ifdef HB_C52_STRICT + /* In CA-Cl*pper ROUND() always returns double item, what in some + * applications may be important due to different formatting rules + * when SET FIXED is ON [druzus] + */ + hb_retndlen( hb_numRound( hb_itemGetND( pNumber ), iDec ), 0, HB_MAX( iDec, 0 ) ); +#else if( iDec == 0 && HB_IS_NUMINT( pNumber ) ) hb_itemReturn( pNumber ); else hb_retnlen( hb_numRound( hb_itemGetND( pNumber ), iDec ), 0, HB_MAX( iDec, 0 ) ); +#endif } else hb_errRT_BASE_SubstR( EG_ARG, 1094, NULL, "ROUND", HB_ERR_ARGS_BASEPARAMS ); diff --git a/harbour/source/rtl/transfrm.c b/harbour/source/rtl/transfrm.c index 6058e5283d..d714e731d4 100644 --- a/harbour/source/rtl/transfrm.c +++ b/harbour/source/rtl/transfrm.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ */ @@ -82,9 +82,8 @@ #define PF_BRITISH 0x0100 /* @E */ #define PF_EXCHANG 0x0100 /* @E. Also means exchange . and , */ #define PF_EMPTY 0x0200 /* @Z */ -#define PF_NUMDATE 0x0400 /* Internal flag. Ignore decimal dot */ -#define PF_WIDTH 0x0800 /* @S */ -#define PF_PARNEGWOS 0x1000 /* @) Similar to PF_PARNEG but without leading spaces */ +#define PF_WIDTH 0x0400 /* @S */ +#define PF_PARNEGWOS 0x0800 /* @) Similar to PF_PARNEG but without leading spaces */ HB_FUNC( TRANSFORM ) { @@ -95,6 +94,7 @@ HB_FUNC( TRANSFORM ) if( pPic && hb_itemGetCLen( pPic ) > 0 ) { + char szPicDate[ 11 ]; char * szPic = hb_itemGetCPtr( pPic ); ULONG ulPicLen = hb_itemGetCLen( pPic ); USHORT uiPicFlags; /* Function flags */ @@ -105,7 +105,7 @@ HB_FUNC( TRANSFORM ) char * szResult; ULONG ulResultPos; - double dValue = 0; + ULONG ulOffset = 0; /* ======================================================= */ /* Analyze picture functions */ @@ -132,9 +132,8 @@ HB_FUNC( TRANSFORM ) switch( hb_charUpper( *szPic ) ) { case HB_CHAR_HT: - case '9': case ' ': - bDone = TRUE; /* End of function string */ + bDone = TRUE; /* End of function string */ break; case '!': uiPicFlags |= PF_UPPER; @@ -147,7 +146,7 @@ HB_FUNC( TRANSFORM ) break; case 'L': case '0': - uiPicFlags |= PF_PADL; + uiPicFlags |= PF_PADL; /* FoxPro/XPP extension */ byParamL = '0'; break; case 'B': @@ -158,7 +157,6 @@ HB_FUNC( TRANSFORM ) break; case 'D': uiPicFlags |= PF_DATE; - uiPicFlags |= PF_NUMDATE; break; case 'E': uiPicFlags |= PF_BRITISH; @@ -168,16 +166,13 @@ HB_FUNC( TRANSFORM ) break; case 'S': uiPicFlags |= PF_WIDTH; - ulParamS = 0; while( ulPicLen > 1 && *( szPic + 1 ) >= '0' && *( szPic + 1 ) <= '9' ) { szPic++; ulPicLen--; - ulParamS = ( ulParamS * 10 ) + ( ( ULONG ) ( *szPic - '0' ) ); } - break; case 'X': uiPicFlags |= PF_DEBIT; @@ -201,22 +196,19 @@ HB_FUNC( TRANSFORM ) char * szExp = hb_itemGetCPtr( pValue ); ULONG ulExpLen = hb_itemGetCLen( pValue ); ULONG ulExpPos = 0; - - char szPicDate[ 11 ]; BOOL bAnyPic = FALSE; BOOL bFound = FALSE; /* Grab enough */ /* Support date function for strings */ - if( ( uiPicFlags & PF_DATE ) || - ( ( uiPicFlags & PF_BRITISH ) && ( uiPicFlags & PF_REMAIN ) ) ) + if( uiPicFlags & ( PF_DATE | PF_BRITISH ) ) { hb_dateFormat( "XXXXXXXX", szPicDate, hb_set.HB_SET_DATEFORMAT ); - szPic = szPicDate; ulPicLen = strlen( szPicDate ); } + szResult = ( char * ) hb_xgrab( ulExpLen + ulPicLen + 1 ); ulResultPos = 0; @@ -365,17 +357,32 @@ HB_FUNC( TRANSFORM ) szResult[ ulResultPos++ ] = ' '; } - if( ( ( uiPicFlags & PF_DATE ) && ( uiPicFlags & PF_BRITISH ) ) || - ( ( uiPicFlags & PF_BRITISH ) && ( uiPicFlags & PF_REMAIN ) ) ) + if( uiPicFlags & PF_BRITISH ) { - szPicDate[ 0 ] = szResult[ 3 ]; - szPicDate[ 1 ] = szResult[ 4 ]; - - szResult[ 3 ] = szResult[ 0 ]; - szResult[ 4 ] = szResult[ 1 ]; - - szResult[ 0 ] = szPicDate[ 0 ]; - szResult[ 1 ] = szPicDate[ 1 ]; + /* CA-Cl*pper do not check result size and always exchanges + * bytes 1-2 with bytes 4-5. It's buffer overflow bug and I do + * not want to replicate it. It also causes that the results of + * @E conversion used for strings smaller then 5 bytes behaves + * randomly. + * In fact precise tests can show that it's not random behavior + * but CA-Cl*pper uses static buffer for result and when current + * one is smaller then 5 bytes then first two bytes are exchanged + * with 4-5 bytes from previous result which was length enough, + * f.e.: + * ? transform( "0123456789", "" ) + * ? transform( "AB", "@E" ) + * ? transform( "ab", "@E" ) + * [druzus] + */ + if( ulResultPos >= 5 ) + { + szPicDate[ 0 ] = szResult[ 0 ]; + szPicDate[ 1 ] = szResult[ 1 ]; + szResult[ 0 ] = szResult[ 3 ]; + szResult[ 1 ] = szResult[ 4 ]; + szResult[ 3 ] = szPicDate[ 0 ]; + szResult[ 4 ] = szPicDate[ 1 ]; + } } } @@ -385,292 +392,250 @@ HB_FUNC( TRANSFORM ) else if( HB_IS_NUMERIC( pValue ) ) { - double dPush; - - int iOrigWidth; - int iOrigDec; int iWidth; /* Width of string */ int iDec; /* Number of decimals */ + int iCount; ULONG i; - ULONG ulBufSize; - int iCount = 0; - - char * szStr; char cPic; - char szPicDate[ 11 ]; + PHB_ITEM pNumber = NULL; - PHB_ITEM pNumber; - PHB_ITEM pWidth; - PHB_ITEM pDec; - - BOOL bFound = FALSE; - BOOL bInit = FALSE; - BOOL bPDec = FALSE; - - dValue = hb_itemGetND( pValue ); - hb_itemGetNLen( pValue, &iOrigWidth, &iOrigDec ); + double dValue = hb_itemGetND( pValue ); /* Support date function for numbers */ if( uiPicFlags & PF_DATE ) { - hb_dateFormat( "99999999", szPicDate, - hb_set.HB_SET_DATEFORMAT ); - + hb_dateFormat( "99999999", szPicDate, hb_set.HB_SET_DATEFORMAT ); szPic = szPicDate; ulPicLen = strlen( szPicDate ); } - /* TODO: maybe replace this 16 with something else */ - ulBufSize = ulPicLen + (ULONG) iOrigWidth + (ULONG) iOrigDec + 16; - szResult = ( char * ) hb_xgrab( ulBufSize ); /* Grab enough */ - *szResult = '\0'; - - for( i = 0; i < ulPicLen && !bFound; i++ ) /* Count number in front */ + for( i = iWidth = iDec = 0; i < ulPicLen; i++ ) { if( szPic[ i ] == '.' ) -/* bFound = !( uiPicFlags & PF_NUMDATE ); / * Exit when numeric */ - bFound = TRUE; + { + while( ++i < ulPicLen ) + { + if( szPic[ i ] == '9' || szPic[ i ] == '#' || + szPic[ i ] == '$' || szPic[ i ] == '*' ) + { + iWidth++; + iDec++; + } + } + if( iDec ) + iWidth++; + break; + } else if( szPic[ i ] == '9' || szPic[ i ] == '#' || szPic[ i ] == '$' || szPic[ i ] == '*' ) - iCount++; + iWidth++; } - iWidth = iCount; - - if( bFound ) /* Did we find a dot */ - { - iDec = 0; - if( i < ulPicLen ) - { /* if not 9999. */ - iWidth++; /* Also adjust iWidth */ - } - for( ; i < ulPicLen; i++ ) - { - if( szPic[ i ] == '9' || - szPic[ i ] == '#' || - szPic[ i ] == '$' || - szPic[ i ] == '*' ) - { - iWidth++; - iDec++; - } - } - } - else - iDec = 0; - - if( ( uiPicFlags & ( PF_DEBIT + PF_PARNEG + PF_PARNEGWOS ) ) && dValue < 0 ) - dPush = -dValue; /* Always push absolute val */ - else - dPush = dValue; - - /* Don't empty the result if the number is not zero */ - if( dPush != 0 && ( uiPicFlags & PF_EMPTY ) ) - uiPicFlags &= ~PF_EMPTY; + iCount = 0; if( iWidth == 0 ) /* Width calculated ?? */ { - iWidth = iOrigWidth; /* Push original width */ - iDec = iOrigDec; /* Push original decimals */ + hb_itemGetNLen( pValue, &iWidth, &iDec ); + if( hb_set.HB_SET_FIXED ) + { + if( HB_IS_NUMINT( pValue ) ) + iWidth += 2 + ( hb_set.HB_SET_DECIMALS << 1 ); + else + iDec = hb_set.HB_SET_DECIMALS; + } + if( iDec ) + iWidth += iDec + 1; + } + else if( iDec > 0 && iWidth - iDec == 1 ) + { + iCount = 1; + iWidth++; } - pNumber = hb_itemPutNDLen( NULL, dPush, -1, iDec ); - pWidth = hb_itemPutNI( NULL, iWidth + ( ( ulPicLen || iDec == 0 ) ? 0 : ( iDec + 1 ) ) ); - pDec = hb_itemPutNI( NULL, iDec ); - - szStr = hb_itemStr( pNumber, pWidth, pDec ); - - hb_itemRelease( pNumber ); - hb_itemRelease( pWidth ); - hb_itemRelease( pDec ); - - if( szStr ) + if( ( uiPicFlags & ( PF_DEBIT | PF_PARNEG | PF_PARNEGWOS ) ) && dValue < 0 ) { - iCount = 0; - - /* Pad with padding char */ - if( uiPicFlags & PF_PADL ) - { - for( i = 0; szStr[ i ] == ' ' && i < ( ULONG ) iWidth; i++ ) - szStr[ i ] = byParamL; - } - - if( ulPicLen ) - for( i = 0; i < ulPicLen; i++ ) - { - cPic = szPic[ i ]; - - if( !bInit && ( cPic == '9' || cPic == '#' || cPic == '$' || cPic == '*' ) ) - bInit = TRUE; - - if( cPic == '9' || cPic == '#' ) - { - if( iCount < iWidth ) - szResult[ i ] = szStr[ iCount++ ]; /* Just copy */ - else - szResult[ i ] = ' '; - } - else if( cPic == '.' && bInit ) - { - bPDec = TRUE; - - if( uiPicFlags & PF_EXCHANG ) /* Exchange . and , */ - { - szResult[ i ] = ','; - iCount++; - } - else - { - if( uiPicFlags & PF_NUMDATE || bPDec ) /* Dot in date */ - { - szResult[ i ] = cPic; - iCount++; - } - else /* Dot in number */ - { - szResult[ i ] = szStr[ iCount++ ]; - } - } - } - else if( cPic == '$' || cPic == '*' ) - { - if( szStr[ iCount ] == ' ' ) - { - szResult[ i ] = cPic; - iCount++; - } - else - szResult[ i ] = szStr[ iCount++ ]; - } - else if( cPic == ',' && bInit ) /* Comma */ - { - if( iCount && isdigit( ( int ) szStr[ iCount - 1 ] ) ) - { /* May we place it */ - if( uiPicFlags & PF_EXCHANG ) - szResult[ i ] = '.'; - else - szResult[ i ] = ','; - } - else - { - if( i && szResult[ i - 1 ] == '*' ) - szResult[ i ] = '*'; - else - szResult[ i ] = ' '; - - if ( i && szResult[ i - 1 ] == '-' ) - { - szResult[ i -1 ] = ' '; - szResult[ i ] = '-'; - } - } - } - else - szResult[ i ] = cPic; - } + /* Always convert absolute val */ + if( HB_IS_NUMINT( pValue ) ) /* workaround for 64bit integer conversion */ + pNumber = hb_itemPutNInt( NULL, - hb_itemGetNInt( pValue ) ); else + pNumber = hb_itemPutND( NULL, -dValue ); + pValue = pNumber; + } + + if( dValue != 0 ) + /* Don't empty the result if the number is not zero */ + uiPicFlags &= ~PF_EMPTY; + + /* allocate 4 additional bytes for possible ") CR" or ") DB" suffix */ + szResult = ( char * ) hb_xgrab( iWidth + 5 ); + hb_itemStrBuf( szResult, pValue, iWidth, iDec ); + if( pNumber ) + hb_itemRelease( pNumber ); + + if( iCount ) + { + iWidth--; + if( *szResult != '0' ) { - hb_strncpy( szResult, szStr, ulBufSize - 1 ); - i = strlen( szResult ); + memset( szResult + 1, '*', iWidth ); + *szResult = '.'; } + else + memmove( szResult, szResult + 1, iWidth ); + szResult[ iWidth ] = '\0'; + } - if( ( uiPicFlags & PF_PARNEG ) && dValue < 0 && !( uiPicFlags & PF_PARNEGWOS ) ) - /* This is a behavior of Clipper, - if exist PF_PARNEG and PF_PARNEGWOS, - PR_PARNEGWOS prevails. */ + /* Pad with padding char */ + if( uiPicFlags & PF_PADL ) + { + for( i = 0; szResult[ i ] == ' '; i++ ) + szResult[ i ] = byParamL; + /* please test it with FoxPro and xbase++ to check + * if they made the same [druzus] + */ + if( i && szResult[ i ] == '-' ) { - for( iCount = 0; ( ULONG ) iCount < i; iCount++ ) - /* Permit to detect overflow when picture init with mask */ + szResult[ 0 ] = '-'; + szResult[ i ] = byParamL; + } + } + + if( ulPicLen == 0 ) + { + if( uiPicFlags & PF_EXCHANG ) + { + for( i = 0; i < ( ULONG ) iWidth; ++i ) { - if( isdigit( ( int ) szResult[ iCount ] ) && - !( szResult[ iCount ] == '0' ) && /* if not PF_PADL */ - ( iCount == 0 || - !isdigit( ( int ) szPic[ iCount ] ) ) ) /* if not mask symbol */ - /* Overflow */ + if( szResult[ i ] == '.' ) { - for( iCount++; ( ULONG ) iCount < i; iCount++ ) - { - if( isdigit( ( int ) szResult[ iCount ] ) ) - szResult[ iCount ] = '*'; - } + szResult[ i ] = ','; break; } + } + } + i = iWidth; + } + else + { + char * szStr = szResult; + + /* allocate 4 additional bytes for possible ") CR" or ") DB" suffix */ + szResult = ( char * ) hb_xgrab( ulPicLen + 5 ); + + for( i = iCount = 0; i < ulPicLen; i++ ) + { + cPic = szPic[ i ]; + if( cPic == '9' || cPic == '#' ) + { + szResult[ i ] = iCount < iWidth ? szStr[ iCount++ ] : ' '; + } + else if( cPic == '$' || cPic == '*' ) + { + if( iCount < iWidth ) + { + szResult[ i ] = szStr[ iCount ] == ' ' ? cPic : szStr[ iCount ]; + iCount++; + } + else + szResult[ i ] = ' '; + } + else if( cPic == '.' && iCount < iWidth ) + { + szResult[ i ] = ( uiPicFlags & PF_EXCHANG ) ? ',' : '.'; + iCount++; + } + else if( cPic == ',' && i && iCount < iWidth ) + { + if( isdigit( ( UCHAR ) szResult[ i - 1 ] ) ) + szResult[ i ] = ( uiPicFlags & PF_EXCHANG ) ? '.' : ','; else { - if( !isdigit( ( int ) szResult[ iCount ] ) || - ( szResult[ iCount ] == '0' && !isdigit( ( int ) szPic[ iCount ] ) ) ) - break; + szResult[ i ] = szResult[ i - 1 ]; + if( szResult[ i - 1 ] == '-' ) + { + szResult[ i - 1 ] = i > 1 && szResult[ i - 2 ] != '$' ? + szResult[ i - 2 ] : ' '; + } } } + else + szResult[ i ] = cPic; + } + hb_xfree( szStr ); + } + + if( dValue < 0 ) + { + /* PF_PARNEGWOS has higher priority then PF_PARNEG */ + if( ( uiPicFlags & PF_PARNEGWOS ) ) + { + iCount = 0; + if( ulPicLen && i > 1 ) + { + if( *szPic == *szResult && ( *szPic == '*' || *szPic == '$' ) && + szResult[ 1 ] == ' ' ) + ++iCount; + } + while( ( ULONG ) iCount + 1 < i && szResult[ iCount + 1 ] == ' ' ) + ++iCount; + +#ifndef HB_C52_STRICT + /* This is not Clipper compatible */ + if( szResult[ iCount ] >= '1' && szResult[ iCount ] <= '9' && + ( ulPicLen == 0 || szPic[ iCount ] == '9' || + szPic[ iCount ] != szResult[ iCount ] ) ) + { + szResult[ iCount ] = '('; + for( ++iCount; ( ULONG ) iCount < i; iCount++ ) + { + if( szResult[ iCount ] >= '0' && szResult[ iCount ] <= '9' && + ( ulPicLen == 0 || szPic[ iCount ] == '9' || + szPic[ iCount ] != szResult[ iCount ] ) ) + szResult[ iCount ] = '*'; + } + } + else +#endif + szResult[ iCount ] = '('; + szResult[ i++ ] = ')'; + } + else if( ( uiPicFlags & PF_PARNEG ) ) + { +#ifndef HB_C52_STRICT + /* This is not Clipper compatible */ + if( *szResult >= '1' && *szResult <= '9' && + ( ulPicLen == 0 || *szPic == '9' || *szPic != *szResult ) ) + { + for( iCount = 1; ( ULONG ) iCount < i; iCount++ ) + { + if( szResult[ iCount ] >= '0' && szResult[ iCount ] <= '9' && + ( ulPicLen == 0 || szPic[ iCount ] == '9' || + szPic[ iCount ] != szResult[ iCount ] ) ) + szResult[ iCount ] = '*'; + } + } +#endif *szResult = '('; szResult[ i++ ] = ')'; + ulOffset = 1; } - if( ( uiPicFlags & PF_PARNEGWOS ) && dValue < 0 ) - { - for( iCount = 0; ( ULONG ) iCount < i; iCount++ ) - /* Permit to detect overflow when picture init with mask */ - { - if( isdigit( ( int ) szResult[ iCount ] ) && - !( szResult[ iCount ] == '0' ) && /* if not PF_PADL */ - ( iCount == 0 || - !isdigit( ( int ) szPic[ iCount ] ) ) ) /* if not mask symbol */ - /* Overflow */ - { - for( iCount++; ( ULONG ) iCount < i; iCount++ ) - { - if( isdigit( ( int ) szResult[ iCount ] ) ) - szResult[ iCount ] = '*'; - } - break; - } - else - { - if( !isdigit( ( int ) szResult[ iCount ] ) || - ( szResult[ iCount ] == '0' && !isdigit( ( int ) szPic[ iCount ] ) ) ) - { - for( ; ( ULONG ) iCount < i; iCount++ ) - { - if( szResult[ iCount ] != ' ' ) - { - if( iCount > 0 ) - szResult[ iCount - 1 ] = '('; - else - *szResult = '('; - - break; - } - } - break; - } - } - } - szResult[ i++ ] = ')'; - } - - if( ( uiPicFlags & PF_CREDIT ) && dValue >= 0 ) - { - szResult[ i++ ] = ' '; - szResult[ i++ ] = 'C'; - szResult[ i++ ] = 'R'; - } - - if( ( uiPicFlags & PF_DEBIT ) && dValue < 0 ) + if( ( uiPicFlags & PF_DEBIT ) ) { szResult[ i++ ] = ' '; szResult[ i++ ] = 'D'; szResult[ i++ ] = 'B'; } - - ulResultPos = i; - szResult[ i ] = '\0'; - - hb_xfree( szStr ); } - else + else if( ( uiPicFlags & PF_CREDIT ) && dValue > 0 ) { - ulResultPos = 0; + szResult[ i++ ] = ' '; + szResult[ i++ ] = 'C'; + szResult[ i++ ] = 'R'; } + + ulResultPos = i; + szResult[ i ] = '\0'; } /* ======================================================= */ @@ -679,27 +644,86 @@ HB_FUNC( TRANSFORM ) else if( HB_IS_DATE( pValue ) ) { - char szPicDate[ 11 ]; char szDate[ 9 ]; - + char * szDateFormat; + char szNewFormat[ 11 ]; UINT nFor; szResult = ( char * ) hb_xgrab( 13 ); + szDateFormat = hb_set.HB_SET_DATEFORMAT; - hb_dateFormat( hb_itemGetDS( pValue, szDate ), szResult, - ( uiPicFlags & PF_BRITISH ) ? - ( hb_set.hb_set_century ? "DD/MM/YYYY" : "DD/MM/YY" ) : - hb_set.HB_SET_DATEFORMAT ); +#ifndef HB_C52_STRICT + if( uiPicFlags & PF_BRITISH ) + { + /* When @E is used CA-Cl*pper do not update date format + * pattern but wrongly moves 4-th and 5-th bytes of + * formatted date to the beginning (see below). It causes + * that date formats formats different then MM?DD?YY[YY] + * are wrongly translated. The code below is not CA-Cl*pper + * compatible but it tries to respect user date format + * [druzus] + */ + const char * szBritish = hb_set.hb_set_century ? + "DDMMYYYY" : "DDMMYY"; + char cLast = 'x'; + for( nFor = 0; nFor < 10; nFor++ ) + { + if( *szBritish == cLast ) + { + szNewFormat[ nFor ] = cLast; + szBritish++; + } + else if( ! *szDateFormat ) + break; + else if( *szBritish && + ( *szDateFormat == 'Y' || *szDateFormat == 'y' || + *szDateFormat == 'D' || *szDateFormat == 'd' || + *szDateFormat == 'M' || *szDateFormat == 'm' ) ) + { + szNewFormat[ nFor ] = cLast = *szBritish++; + do + szDateFormat++; + while( szDateFormat[ -1 ] == szDateFormat[ 0 ] ); + } + else + szNewFormat[ nFor ] = *szDateFormat++; + } + szNewFormat[ nFor ] = '\0'; + szDateFormat = szNewFormat; + } +#endif + + hb_dateFormat( hb_itemGetDS( pValue, szDate ), szResult, szDateFormat ); ulResultPos = strlen( szResult ); +#ifdef HB_C52_STRICT + if( uiPicFlags & PF_BRITISH ) + { + /* replicated wrong Clipper behavior, see note above. + * It's not exact CA-Cl*pper behavior because it does + * not check for size of results and can extract data + * from static memory buffer used in previous conversions + * (see my note for @E in string conversion above) + * but this is buffer overflow and I do not plan to + * replicated it too [druzus] + */ + if( ulResultPos >= 5 ) + { + szNewFormat[ 0 ] = szResult[ 0 ]; + szNewFormat[ 1 ] = szResult[ 1 ]; + szResult[ 0 ] = szResult[ 3 ]; + szResult[ 1 ] = szResult[ 4 ]; + szResult[ 3 ] = szNewFormat[ 0 ]; + szResult[ 4 ] = szNewFormat[ 1 ]; + } + } +#endif if( uiPicFlags & PF_REMAIN ) { - hb_dateFormat( "99999999", szPicDate, - ( uiPicFlags & PF_BRITISH ) ? - ( hb_set.hb_set_century ? "DD/MM/YYYY" : "DD/MM/YY" ) : - hb_set.HB_SET_DATEFORMAT ); - + /* Here we also respect the date format modified for @E [druzus] + */ + hb_dateFormat( "99999999", szPicDate, szDateFormat ); ulPicLen = strlen( szPicDate ); for( nFor = 0; nFor < ulPicLen; nFor++ ) @@ -712,7 +736,6 @@ HB_FUNC( TRANSFORM ) } } } - } /* ======================================================= */ @@ -723,16 +746,20 @@ HB_FUNC( TRANSFORM ) { BOOL bDone = FALSE; BOOL bExit = FALSE; - char cPic; - ulResultPos = 0; + if( uiPicFlags & ( PF_DATE | PF_BRITISH ) ) + { + hb_dateFormat( "99999999", szPicDate, hb_set.HB_SET_DATEFORMAT ); + szPic = szPicDate; + ulPicLen = strlen( szPicDate ); + } + ulResultPos = 0; szResult = ( char * ) hb_xgrab( ulPicLen + 2 ); for( ; ( ulPicLen || !bDone ) && !bExit ; ulResultPos++, szPic++, ulPicLen-- ) { - if( ulPicLen ) cPic = *szPic; else @@ -779,7 +806,6 @@ HB_FUNC( TRANSFORM ) if( !( uiPicFlags & PF_REMAIN ) ) bExit = TRUE; } - } /* ======================================================= */ @@ -793,26 +819,24 @@ HB_FUNC( TRANSFORM ) if( ! bError ) { - /* Trim left and pad with spaces */ - if( uiPicFlags & PF_LEFT ) + if( uiPicFlags & PF_EMPTY ) + memset( szResult, ' ', ulResultPos ); + else if( uiPicFlags & PF_LEFT ) { - - ULONG ulFirstChar = ( ( ( uiPicFlags & PF_PARNEG ) && dValue < 0 && !( uiPicFlags & PF_PARNEGWOS ) ) ? 1: 0 ); + /* Trim left and pad with spaces */ + ULONG ulFirstChar = ulOffset; while( ulFirstChar < ulResultPos && szResult[ ulFirstChar ] == ' ' ) ulFirstChar++; - if( ulFirstChar < ulResultPos ) + if( ulFirstChar > ulOffset && ulFirstChar < ulResultPos ) { - memmove( szResult + ( ( ( uiPicFlags & PF_PARNEG ) && dValue < 0 && !( uiPicFlags & PF_PARNEGWOS ) ) ? 1: 0 ), szResult + ulFirstChar, ulResultPos - ulFirstChar ); - memset( szResult + ulResultPos - ulFirstChar + ( ( ( uiPicFlags & PF_PARNEG ) && dValue < 0 && !( uiPicFlags & PF_PARNEGWOS ) ) ? 1: 0 ), ' ', ulFirstChar ); + memmove( szResult + ulOffset, szResult + ulFirstChar, ulResultPos - ulFirstChar ); + memset( szResult + ulOffset + ulResultPos - ulFirstChar, ' ', ulFirstChar - ulOffset ); } } - if( uiPicFlags & PF_EMPTY ) - memset( szResult, ' ', ulResultPos ); - - hb_retclen_buffer( szResult, ( uiPicFlags & PF_WIDTH && ulResultPos > ulParamS && ulParamS > 0 ) ? ulParamS : ulResultPos ); + hb_retclen_buffer( szResult, ( ulParamS && ulResultPos > ulParamS ) ? ulParamS : ulResultPos ); } } else if( pPic || ISNIL( 2 ) ) /* Picture is an empty string or NIL */ @@ -823,25 +847,18 @@ HB_FUNC( TRANSFORM ) } else if( HB_IS_NUMERIC( pValue ) ) { - int iWidth = 10, iDec; char * szStr; - if( !HB_IS_DOUBLE( pValue ) && hb_set.HB_SET_FIXED ) + if( HB_IS_NUMINT( pValue ) && hb_set.HB_SET_FIXED ) { + int iWidth, iDec; hb_itemGetNLen( pValue, &iWidth, &iDec ); - if( iWidth < 10 ) - { - PHB_ITEM pWidth = hb_itemPutNI( NULL, 2 + iWidth + - ( hb_set.HB_SET_DECIMALS << 1 ) ); - szStr = hb_itemStr( pValue, pWidth, NULL ); - hb_itemRelease( pWidth ); - if( szStr ) - hb_retc_buffer( szStr ); - else - hb_retc( NULL ); - } + iWidth += 2 + ( hb_set.HB_SET_DECIMALS << 1 ); + szStr = hb_xgrab( iWidth + 1 ); + hb_itemStrBuf( szStr, pValue, iWidth, iDec ); + hb_retclen_buffer( szStr, iWidth ); } - if( iWidth >= 10 ) + else { ULONG ulLen; BOOL bFreeReq; diff --git a/harbour/source/vm/classes.c b/harbour/source/vm/classes.c index 910b1f24ff..391f517410 100644 --- a/harbour/source/vm/classes.c +++ b/harbour/source/vm/classes.c @@ -2041,11 +2041,20 @@ static void hb_objSupperDestructorCall( PHB_ITEM pObject, PCLASS pClass ) { if( pbClasses[ uiClass ] == 1 ) { - hb_vmPushSymbol( &s___msgDestructor ); - hb_clsMakeSuperObject( hb_stackAllocItem(), pObject, uiClass ); - hb_vmSend( 0 ); - if( hb_vmRequestQuery() != 0 ) - break; + PMETHOD pDestructor = hb_clsFindMsg( &s_pClasses[ uiClass ], + s___msgDestructor.pDynSym ); + if( pDestructor ) + { + if( pbClasses[ pDestructor->uiSprClass ] == 1 ) + { + hb_vmPushSymbol( &s___msgDestructor ); + hb_clsMakeSuperObject( hb_stackAllocItem(), pObject, uiClass ); + hb_vmSend( 0 ); + if( hb_vmRequestQuery() != 0 ) + break; + pbClasses[ pDestructor->uiSprClass ] |= 2; + } + } } } diff --git a/harbour/tests/transtst.prg b/harbour/tests/transtst.prg new file mode 100644 index 0000000000..1e82fbe58f --- /dev/null +++ b/harbour/tests/transtst.prg @@ -0,0 +1,307 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * test code for TRANSFORM() function + * + * Copyright 2008 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + */ + + +static s_stop := .f. + +proc main() +test() +return + +function transtest( xVal, cPict, cExpect ) +local cResult := transform( xVal, cPict ) +if !cResult == cExpect + s_stop := .t. +endif +return iif( cResult == cExpect, "[OK] ", "[ERROR] ["+cExpect+"] => ") + ; + "[" + cResult + "]" + +proc stop() +if s_stop + ? repl("*",50) + inkey(0) + s_stop := .f. +endif +return + +proc test() +local dt +? transtest( "abcd", "@9!*", "ABCD" ) +? transtest( "abcd", "@_9!*", "ABCD" ) +? transtest( "abcd", "@_9"+chr(9)+"9!9", "aBc" ) +? transtest( "abcd", "@!!!", "ABCD" ) +? transtest( "abcd", "@9", "abcd" ) +? +? transtest( 134.24, "99,999.99", " 134.24" ) +? transtest( 134.24, "@E 99,999.99", " 134,24" ) +? transtest( -134.24,"@E 99,999.99", " -134,24" ) +? transtest( 134.24, "@E99,999.99", " 134,24" ) +? transtest( -134.24, "@E99,999.99", " -134,24" ) +? +? transtest(-7, "@X 9999", " 7 DB") +? transtest(stod("19920509"), "@E", "09/05/92") +? transtest(val("3.10"),"@X", "3.10") +? transtest(0.80,".9999", ".8000" ) +? transtest(-0.80, ".9999", ".****" ) +? transtest(12345.123, "@X99", " 12345.123") +? transtest(-12345.123, "@X99", " 12345.123 DB" ) +? transtest( 123456.78, "@E", " 123456,78") +? transtest(0,"@C 9.99", "0.00") +stop() +#ifdef __HARBOUR__ +dt:=stod("19871231") +set date format to "MM:DD:YYYY" +? transtest( dt, "@E", "31:12:1987" ) +set date format to "DD:MM:YYYY" +? transtest( dt, "@E", "31:12:1987") +set date format to "YYYY:MM:DD" +? transtest( dt, "@E", "31:12:1987") +set date format to "YYYY:DD:MM" +? transtest( dt, "@E", "31:12:1987") +set date format to "YY:MM:DD" +? transtest( dt, "@E", "31:12:87") +set date format to "MM:DD:YY" +? transtest( dt, "@E", "31:12:87") +set date format to "DD:MM:YY" +? transtest( dt, "@E", "31:12:87") +set date format to "" +? transtest( dt, "@E", "<31:12.87>") +set date format to "|YY|MM|DD|" +? transtest( dt, "@E", "|31|12|87|") +set date format to "MM
YY" +? transtest( dt, "@E", "31<12>87") +stop() +#endif + +? transtest( -5, "@(Z $###,##9.99", "( 5.00)" ) +? transtest( -10, "@)Z $###,##9.99", "$ (10.00)" ) +? transtest( -20, "@Z $###,##9.99", "$ -20.00" ) +? transtest(100,"9999.", " 100.") +? transtest(1.1,"@B!99.99", "1.1 ") +? transtest(12.345,"@R 99/99", " /12") +? transtest( "1234567890", "@9", "1234567890") +? transtest( 1234567890, "@9", " 1234567890") +? transtest( 1234, "9 999", "1 234" ) +? transtest( 123.123456, "999.99.99.99", "123.12.45. " ) +? transtest( 123.123456, "$$$.$$.$$.$$", "123.12.45. " ) +? transtest( 123.123456, "***.**.**.**", "123.12.45. " ) +? transtest( 99999, "9.999", "*.***" ) +? transtest( 99, "*.***", "*.***" ) +? transtest( 12345, "9999.", "****." ) +stop() +? transtest(-12345.00, "@(", "( 12345.00)") +? transtest(-12345.00, "@)", " (12345.00)") +? transtest(-123456789.00, "@(", "(123456789.00)") +? transtest(-123456789.00, "@)", "(123456789.00)") +? transtest(-1234567890, "@(", "( 1234567890)") +? transtest(-1234567890, "@)", " (1234567890)") +? transtest(-12345, "@( [999999]", "( 12345])") +? transtest(-12345, "@) [999999]", "[(12345])") +? transtest(-12345, "@( $999999", "( 12345)") +? transtest(-12345, "@) $999999", "$(12345)") +? transtest(-12345, "@( #999999", "( 12345)") +? transtest(-12345, "@) #999999", " (12345)") +? transtest(-12345, "@( $99999", "(12345)") +? transtest(-12345, "@) $99999", "(12345)") +? transtest(-12345, "@( #99999", "(12345)") +? transtest(-12345, "@) #99999", "(12345)") +? transtest(-12345, "@( 6798^999", "(7*8^***)") +? transtest(-12345, "@( 9798^9999", "(718^2345)") +stop() +? +tofix() +return + +proc tofix() +? transtest( 134.24, "@E99,999.99", " 134,24" ) +? transtest( -134.24, "@E99,999.99", " -134,24" ) +? transtest(0.80,".9999", ".8000") +? transtest(-0.80,".9999", ".****") +? transtest(12345.123, "@X99", " 12345.123") +? transtest(-12345.123, "@X99", " 12345.123 DB") +? transtest( 123456.78, "@E", " 123456,78") +? transtest(0,"@C 9.99", "0.00") +? transtest(1.1,"@B!99.99", "1.1 ") +? transtest(-12345, "@) [999999]", "[(12345])") +? transtest(-12345, "@) $999999", "$(12345)") +? transtest(-12345, "@) *999999", "*(12345)") +? transtest(-12345, "@) #999999", " (12345)") +? transtest(-12345, "@) *9$9*999]", "*($12345])") +? transtest(-12345, "@) *999*999]", "* (12345])") +? transtest(-12345, "@) 0999*999]", "0 (12345])") +? transtest(-12345, "@) 1999*999]", "1 (12345])") +? transtest(-12345, "@) *[99*999]", "([ 12345])") +? transtest(-12345, "@) *****999]", "(**12345])") +? transtest(-12345, "@) *1***999]", "(1*12345])") +? transtest(-12345, "@) * 999999]", "* (12345])") +? transtest( -5, "@(Z $###,##9.99", "( 5.00)" ) +? transtest( -10, "@)Z $###,##9.99", "$ (10.00)" ) +? transtest( -5, "@(Z $999,999.99", "( 5.00)" ) +? transtest( -10, "@)Z $999,999.99", "$ (10.00)" ) +? transtest( -5, "@(Z 999,999.99", "( 5.00)" ) +? transtest( -10, "@)Z 999,999.99", " (10.00)" ) +? transtest( -20, "@Z $###,##9.99", "$ -20.00" ) +? transtest(0.1,".9", ".1") +? transtest(0.0,".9", ".0") +? transtest(1,".9", ".*") +? transtest(.456,".9", ".5") +? transtest(123,"99.-", "**.-") +stop() +? transtest(-123.45,"999,999.99", " -123.45") +? transtest(-123456.78,"999,999,999.99", " -123,456.78") +? transtest(-123456.78,"$$$,$$$,$$$.$$", "$$ -123,456.78") +? transtest(-123456.78,"***,***,***.**", "***-123,456.78") +? transtest(123456.78,"@E 888,$$$,$$$.$$", "888.123.456,78") +? transtest(123456.78,"@E 888x,$$$,$$$.$$", "888xx123.456,78") +? transtest(123456.78,"@E 888x,,$$$,$$$.$$", "888xxx123.456,78") +? transtest(123456.78,"@E 8,88x,,$$$,$$$.$$", "8.88xxx123.456,78") +? transtest(123456.78,"@E 8,88x,,$$$,,$$$.$$", "8.88xxx123..456,78") +? transtest(123456.78,"@E 8,88x,,$$$,,$$$.$$77,7", "8.88xxx123..456,7877,7") +? transtest(123456,"@E 8,88x,,$$$,,$$$77,7", "8.88xxx123..45677,7") +? transtest(123456,"@E -,999,999", " -123.456") +? transtest(12345,"@E -,999,999", " - 12.345") +? transtest(12345,"@E -,|999,999", " -| 12.345") +? transtest(12345,"@E ^-,|999,999", "^^-| 12.345") +? transtest(12345,"@E 1-,|999,999", "11-| 12.345") +? transtest(12345,"@E |--,|999,999", "|---| 12.345") +stop() +? transtest(12.34,"@E 99'99", " '12") +? transtest(12.34,"99,99,11", " 12,11") +? transtest(12.34,"@E 99,99,11", " 12,11") +? transtest(12.34,"@E 99,", "12,") +? transtest(12.34,"@E 9,9", "1.2") +? transtest(12.34,"@E ab,cd.ef9,9.99,.--", "abbcd,ef***,* ,.--") +? transtest(12.34,"@E ab,cd,ef9,9.99,.--", "abbcddef1.2,34,.--") +? transtest(12.34,"@E ,ab,cd,ef9,9.99,.--", ",abbcddef1.2,34,.--") +? transtest(12.34,"@E ,,,,99,.99,.--", ",,,,12.,34,.--") +? transtest(124.4,"@E ,,,,9,9.99,.--", ",,,,***,**,.--") +? transtest( 1.2,"@E ,,,,*,*.**,.--", ",,,,**1,20,.--") +? transtest(12.34,"@E ,,,,*,*.**,.--", ",,,,1.2,34,.--") +? transtest(12.34,"@E ,,,,*,*.**,.--,--", ",,,,1.2,34,.--,--") +? transtest(12.34,"@E ,,,,*,*,.,**", ",,,,1.2.,,34") +? transtest(12.34,",,,,*,*,.,**", ",,,,1,2,..34") +? transtest(12.34,",,,,*,*,.,*|,*", ",,,,1,2,..3||4") +? transtest(12.34,",,,,*,*,.,*,*", ",,,,1,2,..3,4") +? transtest(123.345678912,"@E 999.99.99,99.99.", "123,34,67.89, .") +#ifdef __HARBOUR__ +? transtest( 1234567890123456789, "99999999999999999999", " 1234567890123456789" ) +? transtest( -1234567890123456789, "99999999999999999999", "-1234567890123456789" ) +#else +? transtest( 1234567890123456789, "99999999999999999999", " 1234567890123457000" ) +? transtest( -1234567890123456789, "99999999999999999999", "-1234567890123457000" ) +#endif +stop() +set(_SET_DATEFORMAT,"YYYY/MM/DD") +? transtest(12345678,"@D", "1234/56/78") +set(_SET_DATEFORMAT,"YYYY.MM.DD") +? transtest(1234.56789,"@D", "1234.56.9 ") +set(_SET_DATEFORMAT,"YYYY.MM:DD") +? transtest(1234.56789,"@D", "1234.56:79") +? transtest(123.345678912,"@D ", " 123.34:57") +set(_SET_DATEFORMAT,"MM-DD-YYYY") +? transtest(.t.,"@RE <|,yY#lL,|>", "99-99-9999T") +? transtest(.f.,"@RE <|,yY#lL,|>", "99-99-9999F") +? transtest(.t.,"@RD <|,yY#lL,|>", "99-99-9999T") +? transtest(.f.,"@RD <|,yY#lL,|>", "99-99-9999F") +? transtest(.f.,"@DE <|,yY#lL,|>", "9") +? transtest("abcdefghij","@S15! ", "") +? transtest("abcdefghij","@S0! ", "") +? transtest("abcdefghij","@S5! ", "