From 7409f2b74fe6552cf364be7ad043a917fc807bbf Mon Sep 17 00:00:00 2001 From: "David G. Holm" Date: Mon, 17 May 1999 03:34:24 +0000 Subject: [PATCH] See ChangeLog entry 19990516-20:20 EDT David G. Holm --- harbour/ChangeLog | 17 ++ harbour/source/rtl/dates.c | 370 ++++++++++++++++++-------------- harbour/source/rtl/extend.c | 11 +- harbour/source/vm/hvm.c | 2 +- harbour/tests/working/empty.prg | 20 +- 5 files changed, 241 insertions(+), 179 deletions(-) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index e860a78374..7949aa87e1 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,3 +1,20 @@ +19990516-20:20 EDT David G. Holm + * source/rtl/dates.c + - Modified CTOD to perform date validation to only allow dates in the + range allowed by Clipper: January 1, 0 through December 21, 2999. + - Added parameter checking to hb_dtoc. + * source/rtl/extend.c + - Modified _pards to return an empty string ("") for invalid dates. + - Modified _retds to set the Harbour date to 0 if the parameter is missing + or if the parameter is not an 8-character null-terminated string. + * source/vm/hvm.c + - Changed EMPTY case for IT_NUMERIC to IT_INTEGER, because IT_NUMERIC is a + composite of IT_INTEGER, IT_LONG, and IT_DOUBLE, which caused all integer + values to return .T. + * tests/working/empty.prg + - Added SET CENTURY ON and SET DATE BRITISH, and removed text regarding DTOC + needing to be fixed. + 19990516-21:33 CET Eddie Runia * tests/working/set.ch removed diff --git a/harbour/source/rtl/dates.c b/harbour/source/rtl/dates.c index fcaaa12108..a2d3eb1ccd 100644 --- a/harbour/source/rtl/dates.c +++ b/harbour/source/rtl/dates.c @@ -39,79 +39,109 @@ void hb_dateDecode( long julian, long * plDay, long * plMonth, long * plYear ) 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; int count, digit, size = strlen (hb_set.HB_SET_DATEFORMAT); char szDateFormat[ 9 ]; - for( count = 0; count < size; count++) + if( szDate ) { - switch (hb_set.HB_SET_DATEFORMAT [count]) + for( count = 0; count < size; count++) { - case 'D': - case 'd': - if (d_pos == 0) - { - if (m_pos == 0 && y_pos == 0) d_pos = 1; - else if (m_pos == 0 || y_pos == 0) d_pos = 2; - else d_pos = 3; - } - break; - case 'M': - case 'm': - if (m_pos == 0) - { - if (d_pos == 0 && y_pos == 0) m_pos = 1; - else if (d_pos == 0 || y_pos == 0) m_pos = 2; - else m_pos = 3; - } - break; - case 'Y': - case 'y': - if (y_pos == 0) - { - if (m_pos == 0 && d_pos == 0) y_pos = 1; - else if (m_pos == 0 || d_pos == 0) y_pos = 2; - else y_pos = 3; - } - } - } - size = strlen (szDate); - for( count = 0; count < size; count++) - { - digit = szDate [count]; - if (isdigit (digit)) - { - if (d_pos == 1) + switch (hb_set.HB_SET_DATEFORMAT [count]) { - d_value = (d_value * 10) + digit - '0'; - } - else if (m_pos == 1) - { - m_value = (m_value * 10) + digit - '0'; - } - else if (y_pos == 1) - { - y_value = (y_value * 10) + digit - '0'; + case 'D': + case 'd': + if (d_pos == 0) + { + if (m_pos == 0 && y_pos == 0) d_pos = 1; + else if (m_pos == 0 || y_pos == 0) d_pos = 2; + else d_pos = 3; + } + break; + case 'M': + case 'm': + if (m_pos == 0) + { + if (d_pos == 0 && y_pos == 0) m_pos = 1; + else if (d_pos == 0 || y_pos == 0) m_pos = 2; + else m_pos = 3; + } + break; + case 'Y': + case 'y': + if (y_pos == 0) + { + if (m_pos == 0 && d_pos == 0) y_pos = 1; + else if (m_pos == 0 || d_pos == 0) y_pos = 2; + else y_pos = 3; + } } } - else + size = strlen (szDate); + for( count = 0; count < size; count++) { - d_pos--; - m_pos--; - y_pos--; + digit = szDate [count]; + if (isdigit (digit)) + { + if (d_pos == 1) + { + d_value = (d_value * 10) + digit - '0'; + } + else if (m_pos == 1) + { + m_value = (m_value * 10) + digit - '0'; + } + else if (y_pos == 1) + { + y_value = (y_value * 10) + digit - '0'; + } + } + else + { + d_pos--; + m_pos--; + y_pos--; + } + } + if (y_value < 100) + { + count = hb_set.HB_SET_EPOCH % 100; + digit = hb_set.HB_SET_EPOCH / 100; + if (y_value >= count) y_value += (digit * 100); + else y_value += ((digit * 100) + 100); } } - if (y_value < 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) { - count = hb_set.HB_SET_EPOCH % 100; - digit = hb_set.HB_SET_EPOCH / 100; - if (y_value >= count) y_value += (digit * 100); - else y_value += ((digit * 100) + 100); + /* 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; } - sprintf (szDateFormat, "%04i%02i%02i", y_value, m_value, d_value); - _retds( szDateFormat ); + if( bValid ) + { + sprintf (szDateFormat, "%04i%02i%02i", y_value, m_value, d_value); + _retds( szDateFormat ); + } + else _retds( "" ); } char * hb_dtoc (char * szDate, char * szDateFormat) @@ -127,121 +157,129 @@ char * hb_dtoc (char * szDate, char * szDateFormat) * Determine the maximum size of the formatted date string */ size = strlen (hb_set.HB_SET_DATEFORMAT); - if (size > 10) - size = 10; + if (size > 10) size = 10; - format_count = 0; - used_d = used_m = used_y = FALSE; - szPtr = hb_set.HB_SET_DATEFORMAT; - while (format_count < size) + if( szDate && szDateFormat && strlen( szDate ) == 8 ) /* A valid date is always 8 characters */ { - digit = toupper (*szPtr); - szPtr++; - digit_count = 1; - while (toupper (*szPtr) == digit && format_count < size) + format_count = 0; + used_d = used_m = used_y = FALSE; + szPtr = hb_set.HB_SET_DATEFORMAT; + while (format_count < size) { + digit = toupper (*szPtr); szPtr++; - if (format_count + digit_count < size) digit_count++; - } - switch (digit) - { - case 'D': - switch (digit_count) - { - case 4: - if (!used_d && format_count < size) - { - szDateFormat [format_count++] = '0'; - digit_count--; - } - case 3: - if (!used_d && format_count < size) - { - szDateFormat [format_count++] = '0'; - digit_count--; - } - case 2: - if (!used_d && format_count < size) - { - szDateFormat [format_count++] = szDate [6]; - digit_count--; - } - default: - if (!used_d && format_count < size) - { - szDateFormat [format_count++] = szDate [7]; - digit_count--; - } - while (digit_count-- > 0 && format_count < size) szDateFormat [format_count++] = digit; - } - used_d = TRUE; - break; - case 'M': - switch (digit_count) - { - case 4: - if (!used_m && format_count < size) - { - szDateFormat [format_count++] = '0'; - digit_count--; - } - case 3: - if (!used_m && format_count < size) - { - szDateFormat [format_count++] = '0'; - digit_count--; - } - case 2: - if (!used_m && format_count < size) - { - szDateFormat [format_count++] = szDate [4]; - digit_count--; - } - default: - if (!used_m && format_count < size) - { - szDateFormat [format_count++] = szDate [5]; - digit_count--; - } - while (digit_count-- > 0 && format_count < size) szDateFormat [format_count++] = digit; - } - used_m = TRUE; - break; - case 'Y': - switch (digit_count) - { - case 4: - if (!used_y && format_count < size) - { - szDateFormat [format_count++] = szDate [0]; - digit_count--; - } - case 3: - if (!used_y && format_count < size) - { - szDateFormat [format_count++] = szDate [1]; - digit_count--; - } - case 2: - if (!used_y && format_count < size) - { - szDateFormat [format_count++] = szDate [2]; - digit_count--; - } - default: - if (!used_y && format_count < size) - { - szDateFormat [format_count++] = szDate [3]; - digit_count--; - } - while (digit_count-- > 0 && format_count < size) szDateFormat [format_count++] = digit; - } - used_y = TRUE; - break; - default: - while (digit_count-- > 0 && format_count < size) szDateFormat [format_count++] = digit; + digit_count = 1; + while (toupper (*szPtr) == digit && format_count < size) + { + szPtr++; + if (format_count + digit_count < size) digit_count++; + } + switch (digit) + { + case 'D': + switch (digit_count) + { + case 4: + if (!used_d && format_count < size) + { + szDateFormat [format_count++] = '0'; + digit_count--; + } + case 3: + if (!used_d && format_count < size) + { + szDateFormat [format_count++] = '0'; + digit_count--; + } + case 2: + if (!used_d && format_count < size) + { + szDateFormat [format_count++] = szDate [6]; + digit_count--; + } + default: + if (!used_d && format_count < size) + { + szDateFormat [format_count++] = szDate [7]; + digit_count--; + } + while (digit_count-- > 0 && format_count < size) szDateFormat [format_count++] = digit; + } + used_d = TRUE; + break; + case 'M': + switch (digit_count) + { + case 4: + if (!used_m && format_count < size) + { + szDateFormat [format_count++] = '0'; + digit_count--; + } + case 3: + if (!used_m && format_count < size) + { + szDateFormat [format_count++] = '0'; + digit_count--; + } + case 2: + if (!used_m && format_count < size) + { + szDateFormat [format_count++] = szDate [4]; + digit_count--; + } + default: + if (!used_m && format_count < size) + { + szDateFormat [format_count++] = szDate [5]; + digit_count--; + } + while (digit_count-- > 0 && format_count < size) szDateFormat [format_count++] = digit; + } + used_m = TRUE; + break; + case 'Y': + switch (digit_count) + { + case 4: + if (!used_y && format_count < size) + { + szDateFormat [format_count++] = szDate [0]; + digit_count--; + } + case 3: + if (!used_y && format_count < size) + { + szDateFormat [format_count++] = szDate [1]; + digit_count--; + } + case 2: + if (!used_y && format_count < size) + { + szDateFormat [format_count++] = szDate [2]; + digit_count--; + } + default: + if (!used_y && format_count < size) + { + szDateFormat [format_count++] = szDate [3]; + digit_count--; + } + while (digit_count-- > 0 && format_count < size) szDateFormat [format_count++] = digit; + } + used_y = TRUE; + break; + default: + while (digit_count-- > 0 && format_count < size) szDateFormat [format_count++] = digit; + } } } + else + { + /* Not a valid date string, so return a blank date */ + format_count = size; + strncpy( szDateFormat, " ", format_count ); + } szDateFormat [format_count] = 0; return (szDateFormat); } diff --git a/harbour/source/rtl/extend.c b/harbour/source/rtl/extend.c index 76c1368b68..d153e58eea 100644 --- a/harbour/source/rtl/extend.c +++ b/harbour/source/rtl/extend.c @@ -108,7 +108,7 @@ char * _pards( WORD wParam, ... ) /* TODO: implement wArrayIndex use when retrieving an array element */ return ""; - else if( IS_DATE( pItem ) ) + else if( IS_DATE( pItem ) && pItem->value.lDate > 0 ) { hb_dateDecode( pItem->value.lDate, &lDay, &lMonth, &lYear ); @@ -127,9 +127,9 @@ char * _pards( WORD wParam, ... ) return stack.szDate; /* this guaranties good behavior when multithreading */ } else - return "00000000"; + return ""; } - return "00000000"; + return ""; } int _parl( WORD wParam, ... ) @@ -338,7 +338,10 @@ 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 ? */ - stack.Return.value.lDate = hb_dateEncode( lDay, lMonth, lYear ); + if( szDate && strlen( szDate ) == 8 ) + stack.Return.value.lDate = hb_dateEncode( lDay, lMonth, lYear ); + else + stack.Return.value.lDate = 0; } void _retnd( double dNumber ) diff --git a/harbour/source/vm/hvm.c b/harbour/source/vm/hvm.c index d80fa9ca58..2272b2a24f 100644 --- a/harbour/source/vm/hvm.c +++ b/harbour/source/vm/hvm.c @@ -1967,7 +1967,7 @@ HARBOUR EMPTY() _retl( hb_strempty( _parc( 1 ), _parclen( 1 ) ) ); break; - case IT_NUMERIC: + case IT_INTEGER: _retl( ! _parni( 1 ) ); break; diff --git a/harbour/tests/working/empty.prg b/harbour/tests/working/empty.prg index 38bfe0ad06..f96e271429 100644 --- a/harbour/tests/working/empty.prg +++ b/harbour/tests/working/empty.prg @@ -1,13 +1,17 @@ // // Testing Empty() function // -// Date : 29/04/1999 -// Time : 14:30 +// Date : 16/05/1999 +// Time : 21:00 // +#include "set.ch" + function Main() - QOut( "PLEASE SET DATE TO BRITISH / CENTURY ON" ) + HB_SETCENTURY ("ON") // SET CENTURY ON + SET (_SET_DATEFORMAT, "DD/MM/YYYY") // SET DATE BRITISH + QOut( "British date format with century on" ) QOut( "C 'Hallo' ", empty( "Hallo" ) ) QOut( "C '' ", empty( "" ) ) QOut( "C ' ' ", empty( " " ) ) @@ -31,11 +35,11 @@ function Main() Pause() - QOut( "D 10/10/1824 ", empty( ctod("10/10/1824") ) ) - QOut( "D 31/02/1825 ", empty( ctod("31/02/1825") ), " CTOD needs fixing" ) - QOut( "D 99/99/9999 ", empty( ctod("99/99/9999") ) ) - QOut( "D / / ", empty( ctod(" / / ") ) ) - QOut( "D ", empty( ctod("") ), " Another CTOD fix !" ) + QOut( "D 10/10/1824 ", ctod("10/10/1824"), empty( ctod("10/10/1824") ) ) + QOut( "D 31/02/1825 ", ctod("31/02/1825"), empty( ctod("31/02/1825") ) ) + QOut( "D 99/99/9999 ", ctod("99/99/9999"), empty( ctod("99/99/9999") ) ) + QOut( "D / / ", ctod(" / / "), empty( ctod(" / / ") ) ) + QOut( "D ", ctod(""), empty( ctod("") ) ) QOut( "L .T. ", empty( .T. ) ) QOut( "L .F. ", empty( .F. ) ) QOut( "U NIL ", empty( NIL ) )