From 3919c6b914f8dbf10da6eb8a767709f63011245c Mon Sep 17 00:00:00 2001 From: "David G. Holm" Date: Tue, 18 May 1999 22:30:43 +0000 Subject: [PATCH] See ChangeLog entry 19990518-17:30 EDT David G. Holm --- harbour/ChangeLog | 23 ++++++++ harbour/source/rtl/console.c | 10 +++- harbour/source/rtl/dates.c | 92 +++++++++++++++++------------- harbour/source/rtl/extend.c | 63 +++++++++++++------- harbour/source/rtl/math.c | 49 ++++++++++++---- harbour/tests/working/dates.prg | 16 +++--- harbour/tests/working/mathtest.prg | 2 + 7 files changed, 173 insertions(+), 82 deletions(-) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 3126489937..f62019028e 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,3 +1,26 @@ +19990518-17:30 EDT David G. Holm + * source/rtl/console.c + - Use pItem->wLength and pItem->wDec when printing numbers. + * source/rtl/dates.c + - Moved date validation to hb_dateEncode function. + - hb_dtoc now puts date separators in an empty date. + - DAY function now sets stack.Return.wLength to 3. + - MONTH function now sets stack.Return.wLength to 3. + - YEAR function now sets stack.Return.wLength to 5. + * source/rtl/extend.c + - Set stack.Return.wLength and stack.Return.wDec for numbers. + - _retds() now returns 8 spaces for invalid dates. + * source/rtl/math.c + - ABS returns same numeric type as parameter. + - INT returns same numeric type as parameter, but for IT_DOUBLE, the + value is truncated, wLength is set to 10, and wDec is set to 0. + * tests/working/dates.prg + - Removed trailing spaces in strings in OUTSDT calls with multiple items, + because OUTSTD provides a leading space for all items but the first. + * tests/working/mathtest.prg + - Added QOUT(454.14) and QOUT(INT(454)) to debug INT problem with + Borland C++ 3.1, which lead to change to INT in source/rtl/math.c + 19990518-15:20 EDT David G. Holm * source/rtl/set.c - Fixed memory leak in HB_SETCENTURY diff --git a/harbour/source/rtl/console.c b/harbour/source/rtl/console.c index 50975bd6e1..70a056751a 100644 --- a/harbour/source/rtl/console.c +++ b/harbour/source/rtl/console.c @@ -35,6 +35,7 @@ HARBOUR __ACCEPT( void ) /* Internal Clipper function used in ACCEPT command */ static void hb_outstd( WORD wParam ) { char * szText; + PITEM pItem = _param( wParam, IT_ANY ); ULONG ulLenText; char szBuffer [11]; @@ -45,7 +46,7 @@ static void hb_outstd( WORD wParam ) break; case IT_INTEGER: - printf( "%10i", _parni( wParam ) ); + printf( "%*i", pItem->wLength, pItem->value.iNumber ); break; case IT_NIL: @@ -60,7 +61,7 @@ static void hb_outstd( WORD wParam ) break; case IT_LONG: - printf( "%10li", _parnl( wParam ) ); + printf( "%*li", pItem->wLength, pItem->value.iNumber ); break; case IT_STRING: @@ -75,7 +76,10 @@ static void hb_outstd( WORD wParam ) break; case IT_DOUBLE: - printf( "%14.4f", _parnd( wParam ) ); + if( pItem->wDec ) + printf( "%*.*f", pItem->wLength, pItem->wDec, pItem->value.dNumber ); + else + printf( "%*ld", pItem->wLength, (long)pItem->value.dNumber ); break; default: diff --git a/harbour/source/rtl/dates.c b/harbour/source/rtl/dates.c index a2d3eb1ccd..5dacc64980 100644 --- a/harbour/source/rtl/dates.c +++ b/harbour/source/rtl/dates.c @@ -11,14 +11,41 @@ #define _OPTIMIZE_DTOS #endif +extern STACK stack; + long hb_dateEncode( long lDay, long lMonth, long lYear ) { + BOOL bValid = FALSE; long lFactor = ( lMonth < 3 ) ? -1: 0; - return ( 1461 * ( lFactor + 4800 + lYear ) / 4 ) + - ( ( lMonth - 2 - ( lFactor * 12 ) ) * 367 ) / 12 - - ( 3 * ( ( lYear + 4900 + lFactor ) / 100 ) / 4 ) + - lDay - 32075; + /* Perform date validation */ + if (lMonth >= 1 && lMonth <= 12 && lDay >= 1 + && lYear >= 1 & lYear <= 2999) + { + /* Month, year, and lower day limits are simple, + but upper day limit is dependent upon month and leap year */ + BOOL bLeapYear = FALSE; + int aiDayLimit [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + if( lYear % 4 == 0 ) + { + /* Check for leap year (every year that is evenly divisible by 4, + except for centuries, which must be evenly divisible by 400 */ + if( lYear % 100 == 0 ) + { + if( lYear % 400 == 0) bLeapYear = TRUE; /* Leap century */ + } + else bLeapYear = TRUE; /* Leap year */ + + if( bLeapYear ) aiDayLimit[ 1 ] = 29; + } + if( lDay <= (long)aiDayLimit[ (int)lMonth - 1 ] ) bValid = TRUE; + } + if( bValid ) + return ( 1461 * ( lFactor + 4800 + lYear ) / 4 ) + + ( ( lMonth - 2 - ( lFactor * 12 ) ) * 367 ) / 12 - + ( 3 * ( ( lYear + 4900 + lFactor ) / 100 ) / 4 ) + + lDay - 32075; + else return ( 0 ); } void hb_dateDecode( long julian, long * plDay, long * plMonth, long * plYear ) @@ -32,14 +59,13 @@ void hb_dateDecode( long julian, long * plDay, long * plMonth, long * plYear ) julian -= ( ( 1461 * X ) / 4 ) - 31; V = 80 * julian / 2447; U = V / 11; - * plDay = julian - ( 2447 * V / 80 ); - * plMonth = V + 2 - ( U * 12 ); - * plYear = X + U + ( W - 49 ) * 100; + if( plDay ) * plDay = julian - ( 2447 * V / 80 ); + if( plMonth ) * plMonth = V + 2 - ( U * 12 ); + if( plYear ) * plYear = X + U + ( W - 49 ) * 100; } HARBOUR CTOD( void ) { - BOOL bValid = FALSE; char * szDate = _parc( 1 ); int d_value = 0, m_value = 0, y_value = 0; int d_pos = 0, m_pos = 0, y_pos = 0; @@ -114,34 +140,8 @@ HARBOUR CTOD( void ) else y_value += ((digit * 100) + 100); } } - /* Perform date validation before converting to date */ - if (szDate && m_value >= 1 && m_value <= 12 && d_value >= 1 - && y_value >= 0 & y_value <= 2999) - { - /* Month, year, and lower day limits are easy, - but upper day limit is dependent upon month and leap year */ - BOOL bLeapYear = FALSE; - int d_limit [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - if( y_value % 4 == 0 ) - { - /* Check for leap year (every year that is evenly divisible by 4, - except for centuries, which must be evenly divisible by 400 */ - if( y_value % 100 == 0 ) - { - if( y_value % 400 == 0) bLeapYear = TRUE; /* Leap century */ - } - else bLeapYear = TRUE; /* Leap year */ - - if( bLeapYear ) d_limit[ 1 ] = 29; - } - if( d_value <= d_limit[ m_value - 1 ] ) bValid = TRUE; - } - if( bValid ) - { - sprintf (szDateFormat, "%04i%02i%02i", y_value, m_value, d_value); - _retds( szDateFormat ); - } - else _retds( "" ); + sprintf (szDateFormat, "%04i%02i%02i", y_value, m_value, d_value); + _retds( szDateFormat ); } char * hb_dtoc (char * szDate, char * szDateFormat) @@ -276,9 +276,20 @@ char * hb_dtoc (char * szDate, char * szDateFormat) } else { - /* Not a valid date string, so return a blank date */ - format_count = size; - strncpy( szDateFormat, " ", format_count ); + /* Not a valid date string, so return a blank date with separators */ + format_count = size; /* size is either 8 or 10 */ + strncpy( szDateFormat, hb_set.HB_SET_DATEFORMAT, size ); + for (digit_count = 0; digit_count < size; digit_count++) + switch (szDateFormat [digit_count]) + { + case 'D': + case 'd': + case 'M': + case 'm': + case 'Y': + case 'y': + szDateFormat [digit_count] = ' '; + } } szDateFormat [format_count] = 0; return (szDateFormat); @@ -339,6 +350,7 @@ HARBOUR DAY( void ) { hb_dateDecode( pDate->value.lDate, &lDay, &lMonth, &lYear ); _retni( lDay ); + stack.Return.wLength = 3; } else { @@ -358,6 +370,7 @@ HARBOUR MONTH( void ) { hb_dateDecode( pDate->value.lDate, &lDay, &lMonth, &lYear ); _retni( lMonth ); + stack.Return.wLength = 3; } else { @@ -377,6 +390,7 @@ HARBOUR YEAR( void ) { hb_dateDecode( pDate->value.lDate, &lDay, &lMonth, &lYear ); _retni( lYear ); + stack.Return.wLength = 5; } else { diff --git a/harbour/source/rtl/extend.c b/harbour/source/rtl/extend.c index d153e58eea..911618af84 100644 --- a/harbour/source/rtl/extend.c +++ b/harbour/source/rtl/extend.c @@ -106,7 +106,7 @@ char * _pards( WORD wParam, ... ) if( IS_ARRAY( pItem ) && wArrayIndex ) /* TODO: implement wArrayIndex use when retrieving an array element */ - return ""; + return " "; else if( IS_DATE( pItem ) && pItem->value.lDate > 0 ) { @@ -127,9 +127,9 @@ char * _pards( WORD wParam, ... ) return stack.szDate; /* this guaranties good behavior when multithreading */ } else - return ""; + return " "; } - return ""; + return " "; } int _parl( WORD wParam, ... ) @@ -326,10 +326,16 @@ void _retds( char * szDate ) /* szDate must have yyyymmdd format */ { long lDay, lMonth, lYear; - lDay = ( ( szDate[ 6 ] - '0' ) * 10 ) + ( szDate[ 7 ] - '0' ); - lMonth = ( ( szDate[ 4 ] - '0' ) * 10 ) + ( szDate[ 5 ] - '0' ); - lYear = ( ( szDate[ 0 ] - '0' ) * 1000 ) + ( ( szDate[ 1 ] - '0' ) * 100 ) + - ( ( szDate[ 2 ] - '0' ) * 10 ) + ( szDate[ 3 ] - '0' ); + if( szDate && strlen( szDate ) == 8 ) + { + /* Date string has correct length, so attempt to convert */ + lDay = ( ( szDate[ 6 ] - '0' ) * 10 ) + ( szDate[ 7 ] - '0' ); + lMonth = ( ( szDate[ 4 ] - '0' ) * 10 ) + ( szDate[ 5 ] - '0' ); + lYear = ( ( szDate[ 0 ] - '0' ) * 1000 ) + ( ( szDate[ 1 ] - '0' ) * 100 ) + + ( ( szDate[ 2 ] - '0' ) * 10 ) + ( szDate[ 3 ] - '0' ); + } + else lDay = lMonth = lYear = 0; /* Date string missing or bad length, + so force an empty date */ ItemRelease( &stack.Return ); @@ -338,17 +344,15 @@ void _retds( char * szDate ) /* szDate must have yyyymmdd format */ /* QUESTION: Is this ok ? we are going to use a long to store the date */ /* QUESTION: What happens if we use sizeof( LONG ) instead ? */ /* QUESTION: Would it break Clipper language code ? */ - if( szDate && strlen( szDate ) == 8 ) - stack.Return.value.lDate = hb_dateEncode( lDay, lMonth, lYear ); - else - stack.Return.value.lDate = 0; + stack.Return.value.lDate = hb_dateEncode( lDay, lMonth, lYear ); } void _retnd( double dNumber ) { ItemRelease( &stack.Return ); stack.Return.wType = IT_DOUBLE; - stack.Return.wLength = sizeof( double ); /* QUESTION: Is this correct ? */ + stack.Return.wLength = 13; + stack.Return.wDec = 2; stack.Return.value.dNumber = dNumber; } @@ -356,7 +360,8 @@ void _retni( int iNumber ) { ItemRelease( &stack.Return ); stack.Return.wType = IT_INTEGER; - stack.Return.wLength = sizeof( int ); /* QUESTION: Is this correct ? */ + stack.Return.wLength = 10; + stack.Return.wDec = 0; stack.Return.value.iNumber = iNumber; } @@ -364,7 +369,7 @@ void _retl( int iTrueFalse ) { ItemRelease( &stack.Return ); stack.Return.wType = IT_LOGICAL; - stack.Return.wLength = 1; /* QUESTION: Is this correct ? */ + stack.Return.wLength = 3; stack.Return.value.iLogical = iTrueFalse; } @@ -372,7 +377,8 @@ void _retnl( long lNumber ) { ItemRelease( &stack.Return ); stack.Return.wType = IT_LONG; - stack.Return.wLength = sizeof( LONG ); /* QUESTION: Is this correct ? */ + stack.Return.wLength = 10; + stack.Return.wDec = 0; stack.Return.value.lNumber = lNumber; } @@ -446,10 +452,16 @@ void _stords( char * szDate, WORD wParam, ... ) /* szDate must have yyyymmdd for WORD wArrayIndex = 0; long lDay, lMonth, lYear; - lDay = ( ( szDate[ 6 ] - '0' ) * 10 ) + ( szDate[ 7 ] - '0' ); - lMonth = ( ( szDate[ 4 ] - '0' ) * 10 ) + ( szDate[ 5 ] - '0' ); - lYear = ( ( szDate[ 0 ] - '0' ) * 1000 ) + ( ( szDate[ 1 ] - '0' ) * 100 ) + - ( ( szDate[ 2 ] - '0' ) * 10 ) + ( szDate[ 3 ] - '0' ); + if( szDate && strlen( szDate ) == 8 ) + { + /* Date string is valid length, so attempt conversion */ + lDay = ( ( szDate[ 6 ] - '0' ) * 10 ) + ( szDate[ 7 ] - '0' ); + lMonth = ( ( szDate[ 4 ] - '0' ) * 10 ) + ( szDate[ 5 ] - '0' ); + lYear = ( ( szDate[ 0 ] - '0' ) * 1000 ) + ( ( szDate[ 1 ] - '0' ) * 100 ) + + ( ( szDate[ 2 ] - '0' ) * 10 ) + ( szDate[ 3 ] - '0' ); + } + else lDay = lMonth = lYear = 0; /* Date string missing or bad length, + so force an empty date */ va_start( va, wParam ); wArrayIndex = va_arg( va, int ); @@ -496,6 +508,7 @@ void _storl( int iLogical, WORD wParam, ... ) pItemRef = stack.pItems + pItem->value.wItem; ItemRelease( pItemRef ); pItemRef->wType = IT_LOGICAL; + pItemRef->wLength = 3; pItemRef->value.iLogical = iLogical; } } @@ -523,7 +536,9 @@ void _storni( int iValue, WORD wParam, ... ) { pItemRef = stack.pItems + pItem->value.wItem; ItemRelease( pItemRef ); - pItemRef->wType = IT_INTEGER; + pItemRef->wType = IT_INTEGER; + pItemRef->wLength = 10; + pItemRef->wDec = 0; pItemRef->value.iNumber = iValue; } } @@ -551,7 +566,9 @@ void _stornl( long lValue, WORD wParam, ... ) { pItemRef = stack.pItems + pItem->value.wItem; ItemRelease( pItemRef ); - pItemRef->wType = IT_LONG; + pItemRef->wType = IT_LONG; + pItemRef->wLength = 10; + pItemRef->wDec = 0; pItemRef->value.lNumber = lValue; } } @@ -579,7 +596,9 @@ void _stornd( double dValue, WORD wParam, ... ) { pItemRef = stack.pItems + pItem->value.wItem; ItemRelease( pItemRef ); - pItemRef->wType = IT_DOUBLE; + pItemRef->wType = IT_DOUBLE; + pItemRef->wLength = 13; + pItemRef->wDec = 2; pItemRef->value.dNumber = dValue; } } diff --git a/harbour/source/rtl/math.c b/harbour/source/rtl/math.c index b3ea6e78c2..a9fb9fcee9 100644 --- a/harbour/source/rtl/math.c +++ b/harbour/source/rtl/math.c @@ -5,20 +5,35 @@ #include #include +extern STACK stack; + HARBOUR ABS( void ) { if( _pcount() == 1 ) { PITEM pNumber = _param(1, IT_NUMERIC); - - if( pNumber ) + + if( pNumber ) switch( pNumber->wType ) { - double dNumber = _parnd(1); - - if( dNumber >= 0 ) - _retnd( dNumber ); - else - _retnd( -dNumber ); + case IT_INTEGER: + if( pNumber->value.iNumber >= 0 ) + _retni( pNumber->value.iNumber ); + else + _retni( -pNumber->value.iNumber ); + break; + + case IT_LONG: + if( pNumber->value.lNumber >= 0 ) + _retnl( pNumber->value.lNumber ); + else + _retnl( -pNumber->value.lNumber ); + break; + + case IT_DOUBLE: + if( pNumber->value.dNumber >= 0.0 ) + _retnd( pNumber->value.dNumber ); + else + _retnd( -pNumber->value.dNumber ); } else { @@ -71,10 +86,24 @@ HARBOUR INT( void ) if( _pcount() == 1 ) { PITEM pNumber = _param(1, IT_NUMERIC); + double dTemp; - if( pNumber ) + if( pNumber ) switch( pNumber->wType ) { - _retnl( _parnd(1) ); + case IT_INTEGER: + _retni( pNumber->value.iNumber ); + break; + + case IT_LONG: + _retnl( pNumber->value.lNumber ); + break; + + case IT_DOUBLE: + modf( pNumber->value.dNumber, &dTemp ); + _retnd( dTemp ); /* Return integer part of double value */ + stack.Return.wLength = 10; /* Set return length same as int or long */ + stack.Return.wDec = 0; /* Set zero decimal places */ + /* Because _retnl( _parnd( 1 ) ); doesn't work in Borland Turbo C++ 3.1 */ } else { diff --git a/harbour/tests/working/dates.prg b/harbour/tests/working/dates.prg index 596f545ffe..3aa9033f5c 100644 --- a/harbour/tests/working/dates.prg +++ b/harbour/tests/working/dates.prg @@ -22,18 +22,18 @@ local cNewLine := CHR( 10 ) OUTSTD (HB_SETCENTURY ()) OUTSTD (cNewLine, "") - OUTSTD (cNewLine, "dDate = CToD( '02/04/1999' ) => ", dDate := CToD( "02/04/1999" )) + OUTSTD (cNewLine, "dDate = CToD( '02/04/1999' ) =>", dDate := CToD( "02/04/1999" )) - OUTSTD (cNewLine, "ValType( dDate ) = ", ValType( dDate )) + OUTSTD (cNewLine, "ValType( dDate ) =", ValType( dDate )) - OUTSTD (cNewLine, "Day( dDate ) = ", Day( dDate )) - OUTSTD (cNewLine, "Month( dDate ) = ", Month( dDate )) - OUTSTD (cNewLine, "Year( dDate ) = ", Year( dDate ), cNewLine) + OUTSTD (cNewLine, "Day( dDate ) =", Day( dDate )) + OUTSTD (cNewLine, "Month( dDate ) =", Month( dDate )) + OUTSTD (cNewLine, "Year( dDate ) =", Year( dDate ), cNewLine) - OUTSTD (cNewLine, "dDate + 5 = ", dDate2 := dDate + 5) - OUTSTD (cNewLine, "dDate - 5 = ", dDate - 5, cNewLine ) + OUTSTD (cNewLine, "dDate + 5 =", dDate2 := dDate + 5) + OUTSTD (cNewLine, "dDate - 5 =", dDate - 5, cNewLine ) - OUTSTD (cNewLine, "dDate2 - dDate = ", dDate2 - dDate) + OUTSTD (cNewLine, "dDate2 - dDate =", dDate2 - dDate) OUTSTD (cNewLine, "") OUTSTD (cNewLine, dDate, DTOS (dDate)) diff --git a/harbour/tests/working/mathtest.prg b/harbour/tests/working/mathtest.prg index 821506bdf3..19e0913431 100644 --- a/harbour/tests/working/mathtest.prg +++ b/harbour/tests/working/mathtest.prg @@ -10,5 +10,7 @@ qout(acos(43) ) qout(atan(54)) qout(abs(10)) qout(exp(15)) +qout(454.14) qout(int(454.14)) +qout(int(454)) return nil