Added VarDateFromStr API.

diff --git a/ole/variant.c b/ole/variant.c
index 0d32077..70bac6e 100644
--- a/ole/variant.c
+++ b/ole/variant.c
@@ -15,8 +15,9 @@
  *   - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
  *     The prototypes for these are commented out in the oleauto.h file.  They need
  *     to be implemented and cases need to be added to the switches of the  existing APIs.
- *   - The parsing of date for the VarDateFromStr still needs to be done.  I'm currently
- *     working on this.
+ *   - The parsing of date for the VarDateFromStr is not complete.
+ *   - The date manipulations do not support date prior to 1900.
+ *   - The parsing does not accept has many formats has the Windows implementation.
  */
  
 #include "wintypes.h"
@@ -25,6 +26,7 @@
 #include "debug.h"
 #include "winerror.h"
 #include "mapidefs.h"
+#include "parsedt.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -72,6 +74,391 @@
 #define BUFFER_MAX 1024
 static char pBuffer[BUFFER_MAX];
 
+/*
+ * Note a leap year is one that is a multiple of 4
+ * but not of a 100.  Except if it is a multiple of
+ * 400 then it is a leap year.
+ */
+/* According to postgeSQL date parsing functions there is
+ * a leap year when this expression is true.
+ * (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
+ * So according to this there is 365.2515 days in one year.
+ * One + every four years: 1/4 -> 365.25
+ * One - every 100 years: 1/100 -> 365.001
+ * One + every 400 years: 1/400 -> 365.0025
+ */
+static const double DAYS_IN_ONE_YEAR = 365.2515;
+
+
+
+/******************************************************************************
+ *	   DateTimeStringToTm	[INTERNAL]
+ *
+ * Converts a string representation of a date and/or time to a tm structure.
+ *
+ * Note this function uses the postgresql date parsing functions found
+ * in the parsedt.c file.
+ *
+ * Returns TRUE if successfull.
+ *
+ * Note: This function does not parse the day of the week,
+ * daylight savings time. It will only fill the followin fields in
+ * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
+ *
+ ******************************************************************************/
+static BOOL32 DateTimeStringToTm( OLECHAR32* strIn, LCID lcid, struct tm* pTm )
+{
+	BOOL32 res = FALSE;
+	double		fsec;
+	int 		tzp;
+	int 		dtype;
+	int 		nf;
+	char	   *field[MAXDATEFIELDS];
+	int 		ftype[MAXDATEFIELDS];
+	char		lowstr[MAXDATELEN + 1];
+	char* strDateTime = NULL;
+
+	/* Convert the string to ASCII since this is the only format
+	 * postgesql can handle.
+	 */
+	strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+
+	if( strDateTime != NULL )
+	{
+		/* Make sure we don't go over the maximum length
+		 * accepted by postgesql.
+		 */
+		if( strlen( strDateTime ) <= MAXDATELEN )
+		{
+			if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
+			{
+				if( lcid & VAR_DATEVALUEONLY )
+				{
+					/* Get the date information.
+					 * It returns 0 if date information was
+					 * present and 1 if only time information was present.
+					 * -1 if an error occures.
+					 */
+					if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
+					{
+						/* Eliminate the time information since we
+						 * were asked to get date information only.
+						 */
+						pTm->tm_sec = 0;
+						pTm->tm_min = 0;
+						pTm->tm_hour = 0;
+						res = TRUE;
+					}
+				}
+				if( lcid & VAR_TIMEVALUEONLY )
+				{
+					/* Get time information only.
+					 */
+					if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
+					{
+						res = TRUE;
+					}
+				}
+				else
+				{
+					/* Get both date and time information.
+					 * It returns 0 if date information was
+					 * present and 1 if only time information was present.
+					 * -1 if an error occures.
+					 */
+					if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
+					{
+						res = TRUE;
+					}
+				}
+			}
+		}
+		HeapFree( GetProcessHeap(), 0, strDateTime );
+	}
+
+	return res;
+}
+
+
+
+
+
+
+/******************************************************************************
+ *	   TmToDATE 	[INTERNAL]
+ *
+ * The date is implemented using an 8 byte floating-point number.
+ * Days are represented by whole numbers increments starting with 0.00 has
+ * being December 30 1899, midnight.
+ * The hours are expressed as the fractional part of the number.
+ * December 30 1899 at midnight = 0.00
+ * January 1 1900 at midnight = 2.00
+ * January 4 1900 at 6 AM = 5.25
+ * January 4 1900 at noon = 5.50
+ * December 29 1899 at midnight = -1.00
+ * December 18 1899 at midnight = -12.00
+ * December 18 1899 at 6AM = -12.25
+ * December 18 1899 at 6PM = -12.75
+ * December 19 1899 at midnight = -11.00
+ * The tm structure is as follows:
+ * struct tm {
+ *		  int tm_sec;	   seconds after the minute - [0,59]
+ *		  int tm_min;	   minutes after the hour - [0,59]
+ *		  int tm_hour;	   hours since midnight - [0,23]
+ *		  int tm_mday;	   day of the month - [1,31]
+ *		  int tm_mon;	   months since January - [0,11]
+ *		  int tm_year;	   years
+ *		  int tm_wday;	   days since Sunday - [0,6]
+ *		  int tm_yday;	   days since January 1 - [0,365]
+ *		  int tm_isdst;    daylight savings time flag
+ *		  };
+ *
+ * Note: This function does not use the tm_wday, tm_yday, tm_wday,
+ * and tm_isdst fields of the tm structure. And only converts years
+ * after 1900.
+ *
+ * Returns TRUE if successfull.
+ */
+static BOOL32 TmToDATE( struct tm* pTm, DATE *pDateOut )
+{
+	if( (pTm->tm_year - 1900) >= 0 )
+	{
+		int leapYear = 0;
+		
+		/* Start at 1. This is the way DATE is defined.
+		 * January 1, 1900 at Midnight is 1.00.
+		 * January 1, 1900 at 6AM is 1.25.
+		 * and so on.
+		 */
+		*pDateOut = 1;
+
+		/* Add the number of days corresponding to
+		 * tm_year.
+		 */
+		*pDateOut += (pTm->tm_year - 1900) * 365;
+
+		/* Add the leap days in the previous years between now and 1900.
+		 * Note a leap year is one that is a multiple of 4
+		 * but not of a 100.  Except if it is a multiple of
+		 * 400 then it is a leap year.
+		 */
+		*pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
+		*pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
+		*pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
+
+		/* Set the leap year flag if the
+		 * current year specified by tm_year is a
+		 * leap year. This will be used to add a day
+		 * to the day count.
+		 */
+		if( isleap( pTm->tm_year ) )
+			leapYear = 1;
+		
+		/* Add the number of days corresponding to
+		 * the month.
+		 */
+		switch( pTm->tm_mon )
+		{
+		case 2:
+			*pDateOut += 31;
+			break;
+		case 3:
+			*pDateOut += ( 59 + leapYear );
+			break;
+		case 4:
+			*pDateOut += ( 90 + leapYear );
+			break;
+		case 5:
+			*pDateOut += ( 120 + leapYear );
+			break;
+		case 6:
+			*pDateOut += ( 151 + leapYear );
+			break;
+		case 7:
+			*pDateOut += ( 181 + leapYear );
+			break;
+		case 8:
+			*pDateOut += ( 212 + leapYear );
+			break;
+		case 9:
+			*pDateOut += ( 243 + leapYear );
+			break;
+		case 10:
+			*pDateOut += ( 273 + leapYear );
+			break;
+		case 11:
+			*pDateOut += ( 304 + leapYear );
+			break;
+		case 12:
+			*pDateOut += ( 334 + leapYear );
+			break;
+		}
+		/* Add the number of days in this month.
+		 */
+		*pDateOut += pTm->tm_mday;
+	
+		/* Add the number of seconds, minutes, and hours
+		 * to the DATE. Note these are the fracionnal part
+		 * of the DATE so seconds / number of seconds in a day.
+		 */
+		*pDateOut += pTm->tm_hour / 24.0;
+		*pDateOut += pTm->tm_min / 1440.0;
+		*pDateOut += pTm->tm_sec / 86400.0;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/******************************************************************************
+ *	   DateToTm 	[INTERNAL]
+ *
+ * This function converst a windows DATE to a tm structure.
+ *
+ * It does not fill all the fields of the tm structure.
+ * Here is a list of the fields that are filled:
+ * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
+ *
+ * Note this function does not support dates before the January 1, 1900
+ * or ( dateIn < 2.0 ).
+ *
+ * Returns TRUE if successfull.
+ */
+static BOOL32 DateToTm( DATE dateIn, LCID lcid, struct tm* pTm )
+{
+	/* Do not process dates smaller than January 1, 1900.
+	 * Which corresponds to 2.0 in the windows DATE format.
+	 */
+	if( dateIn >= 2.0 )
+	{
+		double decimalPart = 0.0;
+		double wholePart = 0.0;
+
+		pTm->tm_sec = 0;
+		pTm->tm_min = 0;
+		pTm->tm_hour = 0;
+		pTm->tm_mday = 0;
+		pTm->tm_mon = 0;
+		pTm->tm_year = 0;
+		pTm->tm_wday = 0;
+		pTm->tm_yday = 0;
+		pTm->tm_isdst = 0;
+		pTm->tm_gmtoff = 0;
+		pTm->tm_zone = 0;
+	
+		/* Because of the nature of DATE format witch
+		 * associates 2.0 to January 1, 1900. We will
+		 * remove 1.0 from the whole part of the DATE
+		 * so that in the following code 1.0
+		 * will correspond to January 1, 1900.
+		 * This simplyfies the processing of the DATE value.
+		 */
+		dateIn -= 1.0;
+
+		wholePart = (double) floor( dateIn );
+		decimalPart = fmod( dateIn, wholePart );
+
+		if( !(lcid & VAR_TIMEVALUEONLY) )
+		{
+			int nDay = 0;
+			int leapYear = 0;
+			double yearsSince1900 = 0;
+			/* Start at 1900, this where the DATE time 0.0 starts.
+			 */
+			pTm->tm_year = 1900;
+			/* find in what year the day in the "wholePart" falls into.
+			 * add the value to the year field.
+			 */
+			yearsSince1900 = floor( wholePart / DAYS_IN_ONE_YEAR );
+			pTm->tm_year += yearsSince1900;
+			/* determine if this is a leap year.
+			 */
+			if( isleap( pTm->tm_year ) )
+				leapYear = 1;
+			/* find what day of that year does the "wholePart" corresponds to.
+			 * Note: nDay is in [1-366] format
+			 */
+			nDay = (int) ( wholePart - floor( yearsSince1900 * DAYS_IN_ONE_YEAR ) );
+			/* Set the tm_yday value.
+			 * Note: The day is must be converted from [1-366] to [0-365]
+			 */
+			//pTm->tm_yday = nDay - 1;
+			/* find which mount this day corresponds to.
+			 */
+			if( nDay <= 31 )
+			{
+				pTm->tm_mday = nDay;
+				pTm->tm_mon = 0;
+			}
+			else if( nDay <= ( 59 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - 31;
+				pTm->tm_mon = 1;
+			}
+			else if( nDay <= ( 90 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 59 + leapYear );
+				pTm->tm_mon = 2;
+			}
+			else if( nDay <= ( 120 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 90 + leapYear );
+				pTm->tm_mon = 3;
+			}
+			else if( nDay <= ( 151 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 120 + leapYear );
+				pTm->tm_mon = 4;
+			}
+			else if( nDay <= ( 181 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 151 + leapYear );
+				pTm->tm_mon = 5;
+			}
+			else if( nDay <= ( 212 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 181 + leapYear );
+				pTm->tm_mon = 6;
+			}
+			else if( nDay <= ( 243 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 212 + leapYear );
+				pTm->tm_mon = 7;
+			}
+			else if( nDay <= ( 273 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 243 + leapYear );
+				pTm->tm_mon = 8;
+			}
+			else if( nDay <= ( 304 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 273 + leapYear );
+				pTm->tm_mon = 9;
+			}
+			else if( nDay <= ( 334 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 304 + leapYear );
+				pTm->tm_mon = 10;
+			}
+			else if( nDay <= ( 365 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 334 + leapYear );
+				pTm->tm_mon = 11;
+			}
+		}
+		if( !(lcid & VAR_DATEVALUEONLY) )
+		{
+			/* find the number of seconds in this day.
+			 * fractional part times, hours, minutes, seconds.
+			 */
+			pTm->tm_hour = (int) ( decimalPart * 24 );
+			pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
+			pTm->tm_sec = (int) ( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 );
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
 
 
 /******************************************************************************
@@ -2555,12 +2942,9 @@
  */
 HRESULT WINAPI VarDateFromR432(FLOAT fltIn, DATE* pdateOut)
 {
-    unsigned long test = 0;
-
     TRACE( ole, "( %f, %p ), stub\n", fltIn, pdateOut );
 
-    test = (unsigned long) fltIn;
-	if( test < DATE_MIN || test > DATE_MAX )
+    if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
 	{
 		return DISP_E_OVERFLOW;
 	}
@@ -2575,12 +2959,9 @@
  */
 HRESULT WINAPI VarDateFromR832(double dblIn, DATE* pdateOut)
 {
-    unsigned long test = 0;
-
     TRACE( ole, "( %f, %p ), stub\n", dblIn, pdateOut );
 
-    test = (unsigned long) dblIn;
-	if( test < DATE_MIN || test > DATE_MAX )
+	if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
 	{
 		return DISP_E_OVERFLOW;
 	}
@@ -2618,8 +2999,22 @@
 HRESULT WINAPI VarDateFromStr32(OLECHAR32* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
 {
 	HRESULT ret = S_OK;
+    struct tm TM = { 0,0,0,0,0,0,0,0,0 };
 
-    FIXME( ole, "( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
+    TRACE( ole, "( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
+
+    if( DateTimeStringToTm( strIn, lcid, &TM ) )
+    {
+        if( TmToDATE( &TM, pdateOut ) == FALSE )
+        {
+            ret = E_INVALIDARG;
+        }
+    }
+    else
+    {
+        ret = DISP_E_TYPEMISMATCH;
+    }
+
 
 	return ret;
 }
@@ -2780,7 +3175,7 @@
  *		  int tm_hour;	   hours since midnight - [0,23]
  *		  int tm_mday;	   day of the month - [1,31]
  *		  int tm_mon;	   months since January - [0,11]
- *		  int tm_year;	   years since 1900
+ *		  int tm_year;	   years
  *		  int tm_wday;	   days since Sunday - [0,6]
  *		  int tm_yday;	   days since January 1 - [0,365]
  *		  int tm_isdst;    daylight savings time flag
@@ -2788,105 +3183,13 @@
  */
 HRESULT WINAPI VarBstrFromDate32(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR32* pbstrOut)
 {
-	/* If the date is not after the 1900 return an error because
-	 * the tm structure does not allow such dates.
-	 */
-	if( dateIn >= 1.0 )
-	{
-		double decimalPart = 0.0;
-		double wholePart = 0.0;
 		struct tm TM = {0,0,0,0,0,0,0,0,0};
 	 
-		wholePart = (double) (long) dateIn;
-		decimalPart = fmod( dateIn, wholePart );
+    TRACE( ole, "( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
 
-		if( !(lcid & VAR_TIMEVALUEONLY) )
-		{
-			int nDay = 0;
-			int leapYear = 0;
-			/* find in what year the day in the "wholePart" falls into.
-			 */
-			TM.tm_year = (int) ( wholePart / 365.25 );
-			/* determine if this is a leap year.
-			 */
-			if( ( TM.tm_year % 4 ) == 0 )
-				leapYear = 1;
-			/* find what day of that year does the "wholePart" corresponds to.
-			 * the day is [1-366]
-			 */
-			nDay = (int) ( wholePart - ( TM.tm_year * 365.25 ) );
-			TM.tm_yday = nDay - 1;
-			/* find which mount this day corresponds to.
-			 */
-			if( nDay <= 31 )
+    if( DateToTm( dateIn, lcid, &TM ) == FALSE )
 			{
-				TM.tm_mday = nDay;
-				TM.tm_mon = 0;
-			}
-			else if( nDay <= ( 59 + leapYear ) )
-			{
-				TM.tm_mday = nDay - 31;
-				TM.tm_mon = 1;
-			}
-			else if( nDay <= ( 90 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 59 + leapYear );
-				TM.tm_mon = 2;
-			}
-			else if( nDay <= ( 120 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 90 + leapYear );
-				TM.tm_mon = 3;
-			}
-			else if( nDay <= ( 151 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 120 + leapYear );
-				TM.tm_mon = 4;
-			}
-			else if( nDay <= ( 181 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 151 + leapYear );
-				TM.tm_mon = 5;
-			}
-			else if( nDay <= ( 212 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 181 + leapYear );
-				TM.tm_mon = 6;
-			}
-			else if( nDay <= ( 243 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 212 + leapYear );
-				TM.tm_mon = 7;
-			}
-			else if( nDay <= ( 273 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 243 + leapYear );
-				TM.tm_mon = 8;
-			}
-			else if( nDay <= ( 304 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 273 + leapYear );
-				TM.tm_mon = 9;
-			}
-			else if( nDay <= ( 334 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 304 + leapYear );
-				TM.tm_mon = 10;
-			}
-			else if( nDay <= ( 365 + leapYear ) )
-			{
-				TM.tm_mday = nDay - ( 334 + leapYear );
-				TM.tm_mon = 11;
-			}
-		}
-		if( !(lcid & VAR_DATEVALUEONLY) )
-		{
-			/* find the number of seconds in this day.
-			 * fractional part times, hours, minutes, seconds.
-			 */
-			TM.tm_hour = (int) ( decimalPart * 24 );
-			TM.tm_min = (int) ( ( ( decimalPart * 24 ) - TM.tm_hour ) * 60 );
-			TM.tm_sec = (int) ( ( ( decimalPart * 24 * 60 ) - ( TM.tm_hour * 60 ) - TM.tm_min ) * 60 );
+        return E_INVALIDARG;
 		}
 
 		if( lcid & VAR_DATEVALUEONLY )
@@ -2894,15 +3197,9 @@
 		else if( lcid & VAR_TIMEVALUEONLY )
 			strftime( pBuffer, BUFFER_MAX, "%X", &TM );
 		else
-			strftime( pBuffer, 100, "%x %X", &TM );
+        strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
 
 		*pbstrOut = StringDupAtoBstr( pBuffer );
-	}
-	else
-	{
-		FIXME( ole, "( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
-		return E_INVALIDARG;
-	}
 
 	return S_OK;
 }