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, "yyyy<mm>dd" ); ? 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
This commit is contained in:
Przemyslaw Czerpak
2008-03-05 18:10:52 +00:00
parent b968797d44
commit 9cb4e6047d
14 changed files with 845 additions and 334 deletions

View File

@@ -8,6 +8,88 @@
2002-12-01 13:30 UTC+0100 Foo Bar <foo.bar@foobar.org>
*/
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, "yyyy<mm>dd" ); ? 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

View File

@@ -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 );
}

View File

@@ -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

View File

@@ -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 )

View File

@@ -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 };

View File

@@ -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 ) );

View File

@@ -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;

View File

@@ -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 );
}

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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;

View File

@@ -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;
}
}
}
}

307
harbour/tests/transtst.prg Normal file
View File

@@ -0,0 +1,307 @@
/*
* $Id$
*/
/*
* Harbour Project source code:
* test code for TRANSFORM() function
*
* Copyright 2008 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* 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 "<YY:DD.MM>"
? transtest( dt, "@E", "<31:12.87>")
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")
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! <XXXXXXXX>", "<BCDEFGHI>")
? transtest("abcdefghij","@S0! <XXXXXXXX>", "<BCDEFGHI>")
? transtest("abcdefghij","@S5! <XXXXXXXX>", "<BCDE")
stop()
set fixed on
? transtest( 1234, , " 1234" )
? transtest( 1234, "" , " 1234" )
? transtest( 1234, "@" , " 1234" )
? transtest( 1234, "@!", " 1234" )
? transtest( -1234, , " -1234" )
? transtest( -1234, "@" , " -1234" )
#ifdef HB_C52_STRICT
? transtest( round(123,0), , " 123.00" )
? transtest( round(123,0), "@!", " 123.00" )
? transtest( round(123.0,0), , " 123.00" )
? transtest( round(123.0,0),"@!", " 123.00" )
#endif
stop()
? transtest( 1234.567, , " 1234.57" )
? transtest( 1234.567, "", " 1234.57" )
? transtest( 1234.567, "@" , " 1234.57" )
? transtest( 1234.567, "@!", " 1234.57" )
? transtest( -1234.567, , " -1234.57" )
? transtest( -1234.567, "@", " -1234.57" )
? transtest( val("-1.0"), , "-1.00" )
? transtest( val("-1.0"), "@", "-1.00" )
? transtest( val("-123"), , " -123" )
? transtest( val("-123"), "@", " -123" )
? transtest( 0, , " 0" )
? transtest( 0.0, , " 0.00" )
? transtest( val("1"), , " 1" )
? transtest( val("12"), , " 12" )
? transtest( val("123"), , " 123" )
? transtest( val("1234"), , " 1234" )
stop()
set decimal to 3
? transtest( 0.0, , " 0.000" )
? transtest( val("1"), , " 1" )
? transtest( val("12"), , " 12" )
? transtest( val("123"), , " 123" )
? transtest( val("1234"), , " 1234" )
set decimal to 4
? transtest( 0.0, , " 0.0000" )
? transtest( val("1"), , " 1" )
? transtest( val("12"), , " 12" )
? transtest( val("123"), , " 123" )
? transtest( val("1234"), , " 1234" )
set fixed off
stop()
? transtest( -1234, , " -1234" )
? transtest( -1234, "@B", "-1234 " )
? transtest( -1234, "@(", "( 1234)" )
? transtest( -1234, "@)", " (1234)" )
? transtest( -1234, "@B)", "(1234) " )
? transtest( -1234, "@B(", "(1234) " )
? transtest( "( 12)", "@B(", "( 12)" )
? transtest( "( 12)", "@B)", "( 12)" )
? transtest( " 12", "@B(", "12 " )
? transtest( " 12", "@B)", "12 " )
#ifdef __HARBOUR__
? transtest( 1234, "@L", "0000001234" )
? transtest( 1234, "@0", "0000001234" )
? transtest( 1234, "@L(", "0000001234" )
? transtest( 1234, "@0)", "0000001234" )
? transtest( -1234, "@L(", "(000001234)" )
? transtest( -1234, "@0)", "(000001234)" )
/* please test it with FoxPro and xbase++ to check if they give the same result */
? transtest( -1234, "@L", "-000001234" )
? transtest( -1234, "@0", "-000001234" )
#endif
/* FlagShip extensions */
? transtest( -1234, "@Z", " -1234" )
? transtest( 1234, "@Z", " 1234" )
? transtest( -1234, "@F", " -1234" )
? transtest( 1234, "@F", " 1234" )
? transtest( -1234, "@T", " -1234" )
? transtest( 1234, "@T", " 1234" )
? transtest( 123456789.12, "@,39 999,999,999.99", "123,456,789.12" )
? transtest( 123456789.12, "@,39 999,999,999.99", "123,456,789.12" )
? transtest( 123.456, "@R 9 9 9.9", "1 2 3.5" )
stop()
return
#ifndef __HARBOUR__
func stod(s)
local cDf:=set(_SET_DATEFORMAT,"YYYY/MM/DD"), dt
dt:=ctod(stuff(stuff(s,7,0,"/"),5,0,"/"))
set(_SET_DATEFORMAT,cDf)
return dt
#endif

View File

@@ -197,7 +197,7 @@ FUNCTION Main_TRANS()
TEST_LINE( Transform( HB_SToD("19101112") , "9#-9#/##" ) , "1910.11.12" )
TEST_LINE( Transform( HB_SToD("19920101") , "" ) , "1992.01.01" )
TEST_LINE( Transform( HB_SToD("19920101") , "DO THIS " ) , "1992.01.01" )
TEST_LINE( Transform( HB_SToD("19920102") , "@E" ) , "02/01/1992" ) /* Bug in CA-Cl*pper, it returns: "2.91901.02" */
TEST_LINE( Transform( HB_SToD("19920102") , "@E" ) , "02.01.1992" ) /* Bug in CA-Cl*pper, it returns: "2.91901.02" */
TEST_LINE( Transform( 1234 , "@D 9999" ) , "1234.00.0 " )
TEST_LINE( Transform( 1234 , "@BD 9999" ) , "1234.00.0 " )
@@ -216,7 +216,7 @@ FUNCTION Main_TRANS()
TEST_LINE( Transform( HB_SToD("19101112") , "9#-9#/##" ) , "10.11.12" )
TEST_LINE( Transform( HB_SToD("19920101") , "" ) , "92.01.01" )
TEST_LINE( Transform( HB_SToD("19920101") , "DO THIS " ) , "92.01.01" )
TEST_LINE( Transform( HB_SToD("19920102") , "@E" ) , "02/01/92" ) /* Bug in CA-Cl*pper, it returns: "01.92.02" */
TEST_LINE( Transform( HB_SToD("19920102") , "@E" ) , "02.01.92" ) /* Bug in CA-Cl*pper, it returns: "01.92.02" */
TEST_LINE( Transform( 1234 , "@D 9999" ) , "**.**.* " )
TEST_LINE( Transform( 1234 , "@BD 9999" ) , "**.**.* " )
@@ -411,6 +411,21 @@ FUNCTION Main_TRANS()
TEST_LINE( Transform("ABCDEFG", "@DB" ) , "AB.DE.G" )
TEST_LINE( Transform(" CDEFG", "@DB" ) , ".DE.G " )
TEST_LINE( Transform("ABCDEFG", "@DBZ" ) , " " )
#ifdef __CLIPPER__
/* 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 at 1-st 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" )
* [druzus]
*/
TEST_LINE( Transform(".", "@E" ) , " " )
TEST_LINE( Transform(",", "@E" ) , "." )
TEST_LINE( Transform("..", "@E" ) , ","+Chr(0)+"" )
@@ -423,6 +438,7 @@ FUNCTION Main_TRANS()
TEST_LINE( Transform("JKL", "@ER ," ) , "L .JK. " )
TEST_LINE( Transform("OPI", "@ER" ) , "I .OP. " )
TEST_LINE( Transform("JKL", "@ER" ) , "L .JK. " )
#endif
TEST_LINE( Transform(CTOD(""), "@DB") , ". . " )
TEST_LINE( Transform(CTOD(""), "@DBR uiuijk") , ".. . . " )
TEST_LINE( Transform(100, "@B $99999") , "$ 100" )