See ChangeLog entry 19990516-20:20 EDT David G. Holm <dholm@jsd-llc.com>

This commit is contained in:
David G. Holm
1999-05-17 03:34:24 +00:00
parent c5fbdee0e4
commit 7409f2b74f
5 changed files with 241 additions and 179 deletions

View File

@@ -1,3 +1,20 @@
19990516-20:20 EDT David G. Holm <dholm@jsd-llc.com>
* 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

View File

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

View File

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

View File

@@ -1967,7 +1967,7 @@ HARBOUR EMPTY()
_retl( hb_strempty( _parc( 1 ), _parclen( 1 ) ) );
break;
case IT_NUMERIC:
case IT_INTEGER:
_retl( ! _parni( 1 ) );
break;

View File

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