See ChangeLog entry 19990516-20:20 EDT David G. Holm <dholm@jsd-llc.com>
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -1967,7 +1967,7 @@ HARBOUR EMPTY()
|
||||
_retl( hb_strempty( _parc( 1 ), _parclen( 1 ) ) );
|
||||
break;
|
||||
|
||||
case IT_NUMERIC:
|
||||
case IT_INTEGER:
|
||||
_retl( ! _parni( 1 ) );
|
||||
break;
|
||||
|
||||
|
||||
@@ -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 ) )
|
||||
|
||||
Reference in New Issue
Block a user