Ignore:
Timestamp:
Nov 12, 2002, 6:07:48 PM (23 years ago)
Author:
sandervl
Message:

Wine resync

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/oleaut32/variant.c

    r8450 r9400  
    3636
    3737#include "config.h"
    38  
     38
    3939#include <string.h>
    4040#include <stdlib.h>
     
    5353#include "winerror.h"
    5454#include "parsedt.h"
     55#include "typelib.h"
    5556
    5657WINE_DEFAULT_DEBUG_CHANNEL(ole);
     
    100101 * 400 then it is a leap year.
    101102 */
    102 /* According to postgreSQL date parsing functions there is
    103  * a leap year when this expression is true.
    104  * (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
    105  * So according to this there is 365.2515 days in one year.
    106  * One + every four years: 1/4 -> 365.25
    107  * One - every 100 years: 1/100 -> 365.01
    108  * One + every 400 years: 1/400 -> 365.0025
    109  */
    110 /* static const double DAYS_IN_ONE_YEAR = 365.2515;
     103
     104/*
     105 * Use 365 days/year and a manual calculation for leap year days
     106 * to keep arithmetic simple
     107 */
     108static const double DAYS_IN_ONE_YEAR = 365.0;
     109
     110/*
     111 * Token definitions for Varient Formatting
     112 * Worked out by experimentation on a w2k machine. Doesnt appear to be
     113 *   documented anywhere obviously so keeping definitions internally
    111114 *
    112  *  ^^  Might this be the key to an easy way to factor large prime numbers?
    113  *  Let's try using arithmetic.  <lawson_whitney@juno.com> 7 Mar 2000
    114  */
    115 static const double DAYS_IN_ONE_YEAR = 365.2425;
    116 
     115 */
     116/* Pre defined tokens */
     117#define TOK_COPY 0x00
     118#define TOK_END  0x02
     119#define LARGEST_TOKENID 6
     120
     121/* Mapping of token name to id put into the tokenized form
     122   Note testing on W2K shows aaaa and oooo are not parsed??!! */
     123#define TOK_COLON  0x03
     124#define TOK_SLASH  0x04
     125#define TOK_c      0x05
     126#define TOK_d      0x08
     127#define TOK_dd     0x09
     128#define TOK_ddd    0x0a
     129#define TOK_dddd   0x0b
     130#define TOK_ddddd  0x0c
     131#define TOK_dddddd 0x0d
     132#define TOK_w      0x0f
     133#define TOK_ww     0x10
     134#define TOK_m      0x11
     135#define TOK_mm     0x12
     136#define TOK_mmm    0x13
     137#define TOK_mmmm   0x14
     138#define TOK_q      0x06
     139#define TOK_y      0x15
     140#define TOK_yy     0x16
     141#define TOK_yyyy   0x18
     142#define TOK_h      0x1e
     143#define TOK_Hh     0x1f
     144#define TOK_N      0x1a
     145#define TOK_Nn     0x1b
     146#define TOK_S      0x1c
     147#define TOK_Ss     0x1d
     148#define TOK_ttttt  0x07
     149#define TOK_AMsPM  0x2f
     150#define TOK_amspm  0x32
     151#define TOK_AsP    0x30
     152#define TOK_asp    0x33
     153#define TOK_AMPM   0x2e
     154
     155typedef struct tagFORMATTOKEN {
     156    char  *str;
     157    BYTE   tokenSize;
     158    BYTE   tokenId;
     159    int    varTypeRequired;
     160} FORMATTOKEN;
     161
     162typedef struct tagFORMATHDR {
     163    BYTE   len;
     164    BYTE   hex3;
     165    BYTE   hex6;
     166    BYTE   reserved[8];
     167} FORMATHDR;
     168
     169FORMATTOKEN formatTokens[] = {           /* FIXME: Only date formats so far */
     170    {":"     ,   1,  TOK_COLON  , 0},
     171    {"/"     ,   1,  TOK_SLASH  , 0},
     172    {"c"     ,   1,  TOK_c      , VT_DATE},
     173    {"dddddd",   6,  TOK_dddddd , VT_DATE},
     174    {"ddddd" ,   5,  TOK_ddddd  , VT_DATE},
     175    {"dddd"  ,   4,  TOK_dddd   , VT_DATE},
     176    {"ddd"   ,   3,  TOK_ddd    , VT_DATE},
     177    {"dd"    ,   2,  TOK_dd     , VT_DATE},
     178    {"d"     ,   1,  TOK_d      , VT_DATE},
     179    {"ww"    ,   2,  TOK_ww     , VT_DATE},
     180    {"w"     ,   1,  TOK_w      , VT_DATE},
     181    {"mmmm"  ,   4,  TOK_mmmm   , VT_DATE},
     182    {"mmm"   ,   3,  TOK_mmm    , VT_DATE},
     183    {"mm"    ,   2,  TOK_mm     , VT_DATE},
     184    {"m"     ,   1,  TOK_m      , VT_DATE},
     185    {"q"     ,   1,  TOK_q      , VT_DATE},
     186    {"yyyy"  ,   4,  TOK_yyyy   , VT_DATE},
     187    {"yy"    ,   2,  TOK_yy     , VT_DATE},
     188    {"y"     ,   1,  TOK_y      , VT_DATE},
     189    {"h"     ,   1,  TOK_h      , VT_DATE},
     190    {"Hh"    ,   2,  TOK_Hh     , VT_DATE},
     191    {"Nn"    ,   2,  TOK_Nn     , VT_DATE},
     192    {"N"     ,   1,  TOK_N      , VT_DATE},
     193    {"S"     ,   1,  TOK_S      , VT_DATE},
     194    {"Ss"    ,   2,  TOK_Ss     , VT_DATE},
     195    {"ttttt" ,   5,  TOK_ttttt  , VT_DATE},
     196    {"AM/PM" ,   5,  TOK_AMsPM  , VT_DATE},
     197    {"am/pm" ,   5,  TOK_amspm  , VT_DATE},
     198    {"A/P"   ,   3,  TOK_AsP    , VT_DATE},
     199    {"a/p"   ,   3,  TOK_asp    , VT_DATE},
     200    {"AMPM"  ,   4,  TOK_AMPM   , VT_DATE},
     201    {0x00    ,   0,  0          , VT_NULL}
     202};
    117203
    118204/******************************************************************************
     
    248334    int leapYear = 0;
    249335
    250     if( (pTm->tm_year - 1900) < 0 ) return FALSE;
     336    /* Hmmm... An uninitialized Date in VB is December 30 1899 so
     337       Start at 0. This is the way DATE is defined. */
    251338
    252339    /* Start at 1. This is the way DATE is defined.
     
    257344    *pDateOut = 1;
    258345
    259     /* Add the number of days corresponding to
    260      * tm_year.
    261      */
    262     *pDateOut += (pTm->tm_year - 1900) * 365;
    263 
    264     /* Add the leap days in the previous years between now and 1900.
    265      * Note a leap year is one that is a multiple of 4
    266      * but not of a 100.  Except if it is a multiple of
    267      * 400 then it is a leap year.
    268      */
    269     *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
    270     *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
    271     *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
    272 
    273     /* Set the leap year flag if the
    274      * current year specified by tm_year is a
    275      * leap year. This will be used to add a day
    276      * to the day count.
    277      */
    278     if( isleap( pTm->tm_year ) )
    279         leapYear = 1;
    280 
    281     /* Add the number of days corresponding to
    282      * the month.
    283      */
    284     switch( pTm->tm_mon )
    285     {
    286     case 2:
    287         *pDateOut += 31;
    288         break;
    289     case 3:
    290         *pDateOut += ( 59 + leapYear );
    291         break;
    292     case 4:
    293         *pDateOut += ( 90 + leapYear );
    294         break;
    295     case 5:
    296         *pDateOut += ( 120 + leapYear );
    297         break;
    298     case 6:
    299         *pDateOut += ( 151 + leapYear );
    300         break;
    301     case 7:
    302         *pDateOut += ( 181 + leapYear );
    303         break;
    304     case 8:
    305         *pDateOut += ( 212 + leapYear );
    306         break;
    307     case 9:
    308         *pDateOut += ( 243 + leapYear );
    309         break;
    310     case 10:
    311         *pDateOut += ( 273 + leapYear );
    312         break;
    313     case 11:
    314         *pDateOut += ( 304 + leapYear );
    315         break;
    316     case 12:
    317         *pDateOut += ( 334 + leapYear );
    318         break;
     346    if( (pTm->tm_year - 1900) >= 0 ) {
     347
     348        /* Add the number of days corresponding to
     349         * tm_year.
     350         */
     351        *pDateOut += (pTm->tm_year - 1900) * 365;
     352
     353        /* Add the leap days in the previous years between now and 1900.
     354         * Note a leap year is one that is a multiple of 4
     355         * but not of a 100.  Except if it is a multiple of
     356         * 400 then it is a leap year.
     357         * Copied + reversed functionality into TmToDate
     358         */
     359        *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
     360        *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
     361        *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
     362
     363        /* Set the leap year flag if the
     364         * current year specified by tm_year is a
     365         * leap year. This will be used to add a day
     366         * to the day count.
     367         */
     368        if( isleap( pTm->tm_year ) )
     369            leapYear = 1;
     370
     371        /* Add the number of days corresponding to
     372         * the month. (remember tm_mon is 0..11)
     373         */
     374        switch( pTm->tm_mon )
     375        {
     376        case 1:
     377            *pDateOut += 31;
     378            break;
     379        case 2:
     380            *pDateOut += ( 59 + leapYear );
     381            break;
     382        case 3:
     383            *pDateOut += ( 90 + leapYear );
     384            break;
     385        case 4:
     386            *pDateOut += ( 120 + leapYear );
     387            break;
     388        case 5:
     389            *pDateOut += ( 151 + leapYear );
     390            break;
     391        case 6:
     392            *pDateOut += ( 181 + leapYear );
     393            break;
     394        case 7:
     395            *pDateOut += ( 212 + leapYear );
     396            break;
     397        case 8:
     398            *pDateOut += ( 243 + leapYear );
     399            break;
     400        case 9:
     401            *pDateOut += ( 273 + leapYear );
     402            break;
     403        case 10:
     404            *pDateOut += ( 304 + leapYear );
     405            break;
     406        case 11:
     407            *pDateOut += ( 334 + leapYear );
     408            break;
     409        }
     410        /* Add the number of days in this month.
     411         */
     412        *pDateOut += pTm->tm_mday;
     413
     414        /* Add the number of seconds, minutes, and hours
     415         * to the DATE. Note these are the fracionnal part
     416         * of the DATE so seconds / number of seconds in a day.
     417         */
     418    } else {
     419        *pDateOut = 0;
    319420    }
    320     /* Add the number of days in this month.
    321      */
    322     *pDateOut += pTm->tm_mday;
    323 
    324     /* Add the number of seconds, minutes, and hours
    325      * to the DATE. Note these are the fracionnal part
    326      * of the DATE so seconds / number of seconds in a day.
    327      */
     421
    328422    *pDateOut += pTm->tm_hour / 24.0;
    329423    *pDateOut += pTm->tm_min / 1440.0;
     
    346440 * Returns TRUE if successful.
    347441 */
    348 static BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
     442BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
    349443{
    350444    double decimalPart = 0.0;
    351445    double wholePart = 0.0;
    352 
    353     /* Do not process dates smaller than January 1, 1900.
    354      * Which corresponds to 2.0 in the windows DATE format.
    355      */
    356     if( dateIn < 2.0 ) return FALSE;
    357446
    358447    memset(pTm,0,sizeof(*pTm));
     
    365454     * This simplifies the processing of the DATE value.
    366455     */
     456    decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
    367457    dateIn -= 1.0;
    368 
    369458    wholePart = (double) floor( dateIn );
    370     decimalPart = fmod( dateIn, wholePart );
    371459
    372460    if( !(dwFlags & VAR_TIMEVALUEONLY) )
    373461    {
    374         int nDay = 0;
     462        unsigned int nDay = 0;
    375463        int leapYear = 0;
    376464        double yearsSince1900 = 0;
    377         /* Start at 1900, this is where the DATE time 0.0 starts.
    378          */
    379         pTm->tm_year = 1900;
    380         /* find in what year the day in the "wholePart" falls into.
    381          * add the value to the year field.
    382          */
    383         yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
    384         pTm->tm_year += yearsSince1900;
    385         /* determine if this is a leap year.
    386          */
    387         if( isleap( pTm->tm_year ) )
    388         {
    389             leapYear = 1;
    390             wholePart++;
    391         }
    392 
    393         /* find what day of that year the "wholePart" corresponds to.
    394          * Note: nDay is in [1-366] format
    395          */
    396         nDay = (int) ( wholePart - floor( yearsSince1900 * DAYS_IN_ONE_YEAR ) );
    397         /* Set the tm_yday value.
    398          * Note: The day must be converted from [1-366] to [0-365]
    399          */
    400         /*pTm->tm_yday = nDay - 1;*/
    401         /* find which month this day corresponds to.
    402          */
    403         if( nDay <= 31 )
    404         {
    405             pTm->tm_mday = nDay;
    406             pTm->tm_mon = 0;
    407         }
    408         else if( nDay <= ( 59 + leapYear ) )
    409         {
    410             pTm->tm_mday = nDay - 31;
    411             pTm->tm_mon = 1;
    412         }
    413         else if( nDay <= ( 90 + leapYear ) )
    414         {
    415             pTm->tm_mday = nDay - ( 59 + leapYear );
    416             pTm->tm_mon = 2;
    417         }
    418         else if( nDay <= ( 120 + leapYear ) )
    419         {
    420             pTm->tm_mday = nDay - ( 90 + leapYear );
    421             pTm->tm_mon = 3;
    422         }
    423         else if( nDay <= ( 151 + leapYear ) )
    424         {
    425             pTm->tm_mday = nDay - ( 120 + leapYear );
    426             pTm->tm_mon = 4;
    427         }
    428         else if( nDay <= ( 181 + leapYear ) )
    429         {
    430             pTm->tm_mday = nDay - ( 151 + leapYear );
    431             pTm->tm_mon = 5;
    432         }
    433         else if( nDay <= ( 212 + leapYear ) )
    434         {
    435             pTm->tm_mday = nDay - ( 181 + leapYear );
    436             pTm->tm_mon = 6;
    437         }
    438         else if( nDay <= ( 243 + leapYear ) )
    439         {
    440             pTm->tm_mday = nDay - ( 212 + leapYear );
    441             pTm->tm_mon = 7;
    442         }
    443         else if( nDay <= ( 273 + leapYear ) )
    444         {
    445             pTm->tm_mday = nDay - ( 243 + leapYear );
    446             pTm->tm_mon = 8;
    447         }
    448         else if( nDay <= ( 304 + leapYear ) )
    449         {
    450             pTm->tm_mday = nDay - ( 273 + leapYear );
    451             pTm->tm_mon = 9;
    452         }
    453         else if( nDay <= ( 334 + leapYear ) )
    454         {
    455             pTm->tm_mday = nDay - ( 304 + leapYear );
    456             pTm->tm_mon = 10;
    457         }
    458         else if( nDay <= ( 365 + leapYear ) )
    459         {
    460             pTm->tm_mday = nDay - ( 334 + leapYear );
    461             pTm->tm_mon = 11;
     465
     466        /* Hard code dates smaller than January 1, 1900. */
     467        if( dateIn < 2.0 ) {
     468            pTm->tm_year = 1899;
     469            pTm->tm_mon  = 11; /* December as tm_mon is 0..11 */
     470            if( dateIn < 1.0 ) {
     471                pTm->tm_mday  = 30;
     472                dateIn = dateIn * -1.0; /* Ensure +ve for time calculation */
     473                decimalPart = decimalPart * -1.0; /* Ensure +ve for time calculation */
     474            } else {
     475                pTm->tm_mday  = 31;
     476            }
     477
     478        } else {
     479
     480            /* Start at 1900, this is where the DATE time 0.0 starts.
     481             */
     482            pTm->tm_year = 1900;
     483            /* find in what year the day in the "wholePart" falls into.
     484             * add the value to the year field.
     485             */
     486            yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
     487            pTm->tm_year += yearsSince1900;
     488            /* determine if this is a leap year.
     489             */
     490            if( isleap( pTm->tm_year ) )
     491            {
     492                leapYear = 1;
     493                wholePart++;
     494            }
     495
     496            /* find what day of that year the "wholePart" corresponds to.
     497             * Note: nDay is in [1-366] format
     498             */
     499            nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
     500
     501            /* Remove the leap days in the previous years between now and 1900.
     502             * Note a leap year is one that is a multiple of 4
     503             * but not of a 100.  Except if it is a multiple of
     504             * 400 then it is a leap year.
     505             * Copied + reversed functionality from TmToDate
     506             */
     507            nDay -= ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
     508            nDay += ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
     509            nDay -= ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
     510
     511            /* Set the tm_yday value.
     512             * Note: The day must be converted from [1-366] to [0-365]
     513             */
     514            /*pTm->tm_yday = nDay - 1;*/
     515            /* find which month this day corresponds to.
     516             */
     517            if( nDay <= 31 )
     518            {
     519                pTm->tm_mday = nDay;
     520                pTm->tm_mon = 0;
     521            }
     522            else if( nDay <= ( 59 + leapYear ) )
     523            {
     524                pTm->tm_mday = nDay - 31;
     525                pTm->tm_mon = 1;
     526            }
     527            else if( nDay <= ( 90 + leapYear ) )
     528            {
     529                pTm->tm_mday = nDay - ( 59 + leapYear );
     530                pTm->tm_mon = 2;
     531            }
     532            else if( nDay <= ( 120 + leapYear ) )
     533            {
     534                pTm->tm_mday = nDay - ( 90 + leapYear );
     535                pTm->tm_mon = 3;
     536            }
     537            else if( nDay <= ( 151 + leapYear ) )
     538            {
     539                pTm->tm_mday = nDay - ( 120 + leapYear );
     540                pTm->tm_mon = 4;
     541            }
     542            else if( nDay <= ( 181 + leapYear ) )
     543            {
     544                pTm->tm_mday = nDay - ( 151 + leapYear );
     545                pTm->tm_mon = 5;
     546            }
     547            else if( nDay <= ( 212 + leapYear ) )
     548            {
     549                pTm->tm_mday = nDay - ( 181 + leapYear );
     550                pTm->tm_mon = 6;
     551            }
     552            else if( nDay <= ( 243 + leapYear ) )
     553            {
     554                pTm->tm_mday = nDay - ( 212 + leapYear );
     555                pTm->tm_mon = 7;
     556            }
     557            else if( nDay <= ( 273 + leapYear ) )
     558            {
     559                pTm->tm_mday = nDay - ( 243 + leapYear );
     560                pTm->tm_mon = 8;
     561            }
     562            else if( nDay <= ( 304 + leapYear ) )
     563            {
     564                pTm->tm_mday = nDay - ( 273 + leapYear );
     565                pTm->tm_mon = 9;
     566            }
     567            else if( nDay <= ( 334 + leapYear ) )
     568            {
     569                pTm->tm_mday = nDay - ( 304 + leapYear );
     570                pTm->tm_mon = 10;
     571            }
     572            else if( nDay <= ( 365 + leapYear ) )
     573            {
     574                pTm->tm_mday = nDay - ( 334 + leapYear );
     575                pTm->tm_mon = 11;
     576            }
    462577        }
    463578    }
     
    466581        /* find the number of seconds in this day.
    467582         * fractional part times, hours, minutes, seconds.
     583         * Note: 0.1 is hack to ensure figures come out in whole numbers
     584         *   due to floating point inaccuracies
    468585         */
    469586        pTm->tm_hour = (int) ( decimalPart * 24 );
    470587        pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
    471         pTm->tm_sec = (int) ( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 );
     588        /* Note: 0.1 is hack to ensure seconds come out in whole numbers
     589             due to floating point inaccuracies */
     590        pTm->tm_sec = (int) (( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 ) + 0.1);
    472591    }
    473592    return TRUE;
     
    521640        break;
    522641    case( VT_BSTR ):
     642    case( VT_DISPATCH ):
     643    case( VT_UNKNOWN ):
    523644        size = sizeof(void*);
    524645        break;
    525646    case( VT_CY ):
    526     case( VT_DISPATCH ):
    527     case( VT_UNKNOWN ):
    528     case( VT_DECIMAL ):
     647        size = sizeof(CY);
     648        break;
     649    case( VT_DECIMAL ):         /* hmm, tricky, DECIMAL is only VT_BYREF */
    529650    default:
    530651        FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
     
    536657/******************************************************************************
    537658 *         StringDupAtoBstr             [INTERNAL]
    538  * 
     659 *
    539660 */
    540661static BSTR StringDupAtoBstr( char* strIn )
     
    563684   nSign = (d >= 0.0) ? 1 : -1;
    564685    d = fabs( d );
    565    
     686
    566687        /* Remove the decimals.
    567688         */
     
    630751                str[0] = '\0';
    631752                strToken = strtok( pNewString, strOfCharToRemove );
    632                 while( strToken != NULL ) { 
     753                while( strToken != NULL ) {
    633754                        strcat( str, strToken );
    634755                        strToken = strtok( NULL, strOfCharToRemove );
     
    671792        int nTokens = 0;
    672793        LPSTR pChar = NULL;
    673        
     794
    674795        /* Check if we have a valid argument
    675796         */
     
    684805                 */
    685806                strToken = strtok( strRealString, " " );
    686                 while( strToken != NULL ) { 
    687                         nTokens++;             
    688                         strToken = strtok( NULL, " " ); 
     807                while( strToken != NULL ) {
     808                        nTokens++;
     809                        strToken = strtok( NULL, " " );
    689810                }
    690811
     
    778899                case '7':
    779900                case '8':
    780                 case '9': 
     901                case '9':
    781902                        if( bFirstDigitsProcessed == FALSE )
    782903                        {
     
    824945                /* If DecimalPoint...
    825946                 */
    826                 case '.': 
     947                case '.':
    827948                        if( bDecimalPointProcessed ||
    828949                                bSecondDigitsProcessed ||
     
    8941015        vtFrom = V_VT(ps) & VT_TYPEMASK;
    8951016
    896        
     1017
    8971018        /* Note: Since "long" and "int" values both have 4 bytes and are
    8981019         * both signed integers "int" will be treated as "long" in the
     
    9011022         */
    9021023
    903         /* Trivial Case: If the coercion is from two types that are 
     1024        /* Trivial Case: If the coercion is from two types that are
    9041025         * identical then we can blindly copy from one argument to another.*/
    9051026        if ((vt==vtFrom))
     
    12471368                }
    12481369                break;
    1249                
     1370
    12501371        case( VT_R4 ):
    12511372                switch( vtFrom )
     
    16101731                break;
    16111732        }
    1612        
     1733
    16131734        return res;
    16141735}
     
    16561777                        res = DISP_E_BADVARTYPE;
    16571778                }
    1658                        
     1779
    16591780    }
    16601781    else
     
    16621783        res = ValidateVtRange( vt );
    16631784    }
    1664                
     1785
    16651786        return res;
    16661787}
     
    16891810                        res = DISP_E_BADVARTYPE;
    16901811                }
    1691                        
     1812
    16921813    }
    16931814    else
     
    16951816        res = ValidateVtRange( vt );
    16961817    }
    1697                
     1818
    16981819        return res;
    16991820}
     
    17701891      }
    17711892    }
    1772        
     1893
    17731894    /*
    17741895     * Empty all the fields and mark the type as empty.
     
    18001921  {
    18011922    res = VariantClear( pvargDest );
    1802                
     1923
    18031924    if( res == S_OK )
    18041925    {
     
    18541975          }
    18551976        }
    1856        
     1977
    18571978        V_VT(pvargDest) = V_VT(pvargSrc);
    1858       }     
     1979      }
    18591980    }
    18601981  }
     
    18802001  if( res != S_OK )
    18812002    return res;
    1882  
     2003
    18832004  if( V_VT(pvargSrc) & VT_BYREF )
    18842005  {
     
    19312052                 * If the inner Variant itself contains an
    19322053                 * other inner variant the E_INVALIDARG error is
    1933                  * returned. 
     2054                 * returned.
    19342055                 */
    19352056                if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
     
    19482069                   */
    19492070                  (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
    1950                  
     2071
    19512072                  /* Dereference the inner variant.
    19522073                   */
     
    20112132        VARIANTARG varg;
    20122133        VariantInit( &varg );
    2013        
     2134
    20142135        TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
     2136    TRACE("Src Var:\n");
     2137    dump_Variant(pvargSrc);
    20152138
    20162139        /* validate our source argument.
     
    20562179                                VariantClear( &Variant );
    20572180                        }
    2058        
     2181
    20592182                }
    20602183                else
     
    20682191         */
    20692192        VariantClear( &varg );
    2070        
     2193
    20712194        /* set the type of the destination
    20722195         */
     
    20742197                V_VT(pvargDest) = vt;
    20752198
     2199    TRACE("Dest Var:\n");
     2200    dump_Variant(pvargDest);
     2201
    20762202        return res;
    20772203}
     
    20952221
    20962222        *pbOut = (BYTE) sIn;
    2097        
     2223
    20982224        return S_OK;
    20992225}
     
    21142240
    21152241        *pbOut = (BYTE) lIn;
    2116        
     2242
    21172243        return S_OK;
    21182244}
     
    21352261
    21362262        *pbOut = (BYTE) fltIn;
    2137        
     2263
    21382264        return S_OK;
    21392265}
     
    22642390         */
    22652391        dValue = atof( pNewString );
    2266        
     2392
    22672393        /* We don't need the string anymore so free it.
    22682394         */
     
    22882414HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
    22892415   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
    2290    
     2416
    22912417   if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
    2292    
     2418
    22932419   *pbOut = (BYTE)t;
    22942420   return S_OK;
     
    23032429
    23042430        *psOut = (short) bIn;
    2305        
     2431
    23062432        return S_OK;
    23072433}
     
    23222448
    23232449        *psOut = (short) lIn;
    2324        
     2450
    23252451        return S_OK;
    23262452}
     
    24702596         */
    24712597        dValue = atof( pNewString );
    2472        
     2598
    24732599        /* We don't need the string anymore so free it.
    24742600         */
     
    24942620HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
    24952621   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
    2496    
     2622
    24972623   if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
    2498    
     2624
    24992625   *psOut = (SHORT)t;
    25002626   return S_OK;
     
    26632789         */
    26642790        dValue = atof( pNewString );
    2665        
     2791
    26662792        /* We don't need the string anymore so free it.
    26672793         */
     
    26872813HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
    26882814   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
    2689    
     2815
    26902816   if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
    2691    
     2817
    26922818   *plOut = (LONG)t;
    26932819   return S_OK;
     
    28382964         */
    28392965        dValue = atof( pNewString );
    2840        
     2966
    28412967        /* We don't need the string anymore so free it.
    28422968         */
     
    28612987HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
    28622988   *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
    2863    
     2989
    28642990   return S_OK;
    28652991}
     
    29813107        LPSTR pNewString = NULL;
    29823108
    2983         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pdblOut );
     3109        pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
     3110        TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
    29843111
    29853112        /* Check if we have a valid argument
    29863113         */
    2987         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
    29883114        RemoveCharacterFromString( pNewString, "," );
    29893115        if( IsValidRealString( pNewString ) == FALSE )
     
    29953121         */
    29963122        dValue = atof( pNewString );
    2997        
     3123
    29983124        /* We don't need the string anymore so free it.
    29993125         */
     
    30113137HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
    30123138   *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
    3013    
     3139   TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
    30143140   return S_OK;
    30153141}
     
    31003226 *
    31013227 * The formats for the date part are has follows:
    3102  * mm/[dd/][yy]yy 
     3228 * mm/[dd/][yy]yy
    31033229 * [dd/]mm/[yy]yy
    3104  * [yy]yy/mm/dd 
     3230 * [yy]yy/mm/dd
    31053231 * January dd[,] [yy]yy
    31063232 * dd January [yy]yy
     
    31093235 *
    31103236 * The formats for the date and time string are has follows.
    3111  * date[whitespace][time] 
     3237 * date[whitespace][time]
    31123238 * [time][whitespace]date
    31133239 *
     
    31353261        ret = DISP_E_TYPEMISMATCH;
    31363262    }
    3137 
    3138 
     3263    TRACE("Return value %f\n", *pdateOut);
    31393264        return ret;
    31403265}
     
    32183343
    32193344        *pbstrOut =  StringDupAtoBstr( pBuffer );
    3220        
     3345
    32213346        return S_OK;
    32223347}
     
    32773402 */
    32783403HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
    3279         FIXME("([cyIn], %08lx, %08lx, %p), stub.\n", lcid, dwFlags, pbstrOut);
    3280         return E_NOTIMPL;
    3281 }
    3282 
    3283  
     3404    HRESULT rc = S_OK;
     3405    double curVal = 0.0;
     3406
     3407        TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
     3408
     3409    /* Firstly get the currency in a double, then put it in a buffer */
     3410    rc = VarR8FromCy(cyIn, &curVal);
     3411    if (rc == S_OK) {
     3412        sprintf(pBuffer, "%g", curVal);
     3413        *pbstrOut = StringDupAtoBstr( pBuffer );
     3414    }
     3415        return rc;
     3416}
     3417
     3418
    32843419/******************************************************************************
    32853420 *              VarBstrFromDate         [OLEAUT32.114]
     
    33163451    memset( &TM, 0, sizeof(TM) );
    33173452
    3318     TRACE("( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
     3453    TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
    33193454
    33203455    if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
     
    33303465        strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
    33313466
     3467        TRACE("result: %s\n", pBuffer);
    33323468                *pbstrOut = StringDupAtoBstr( pBuffer );
    3333 
    33343469        return S_OK;
    33353470}
     
    35083643
    35093644        HeapFree( GetProcessHeap(), 0, pNewString );
    3510        
     3645
    35113646        return ret;
    35123647}
     
    35553690      if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
    35563691      else *pboolOut = 0;
    3557      
     3692
    35583693      return S_OK;
    35593694}
     
    36883823         */
    36893824        dValue = atof( pNewString );
    3690  
     3825
    36913826        /* We don't need the string anymore so free it.
    36923827         */
     
    37583893HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
    37593894   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
    3760    
     3895
    37613896   if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
    3762    
     3897
    37633898   *pcOut = (CHAR)t;
    37643899   return S_OK;
     
    38874022         */
    38884023        dValue = atof( pNewString );
    3889  
     4024
    38904025        /* We don't need the string anymore so free it.
    38914026         */
     
    39364071        TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
    39374072
    3938         if( ulIn < UI2_MIN || ulIn > UI2_MAX )
     4073        if( ulIn > UI2_MAX )
    39394074        {
    39404075                return DISP_E_OVERFLOW;
     
    39684103         */
    39694104        dValue = atof( pNewString );
    3970  
     4105
    39714106        /* We don't need the string anymore so free it.
    39724107         */
     
    39924127HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
    39934128   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
    3994    
     4129
    39954130   if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
    3996      
     4131
    39974132   *pusOut = (USHORT)t;
    3998    
     4133
    39994134   return S_OK;
    40004135}
     
    40364171        TRACE("( %ld, %p ), stub\n", lIn, pulOut );
    40374172
    4038         if( lIn < UI4_MIN )
     4173        if( lIn < 0 )
    40394174        {
    40404175                return DISP_E_OVERFLOW;
     
    41404275HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
    41414276   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
    4142    
     4277
    41434278   if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
    41444279
     
    41804315      pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
    41814316      if (lIn < 0) pcyOut->s.Hi--;
    4182    
     4317
    41834318      return S_OK;
    41844319}
     
    41934328   pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
    41944329   if (fltIn < 0) pcyOut->s.Hi--;
    4195    
     4330
    41964331   return S_OK;
    41974332}
     
    42254360/**********************************************************************
    42264361 *              VarCyFromStr [OLEAUT32.104]
     4362 * FIXME: Never tested with decimal seperator other than '.'
    42274363 */
    42284364HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
    4229         FIXME("(%p, %08lx, %08lx, %p), stub.\n", strIn, lcid, dwFlags, pcyOut);
    4230         return E_NOTIMPL;
    4231 }
    4232 
    4233  
     4365
     4366        LPSTR   pNewString      = NULL;
     4367    char   *decSep          = NULL;
     4368    char   *strPtr,*curPtr  = NULL;
     4369    int size, rc;
     4370    double currencyVal = 0.0;
     4371
     4372
     4373        pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
     4374        TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
     4375
     4376    /* Get locale information - Decimal Seperator (size includes 0x00) */
     4377    size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
     4378    decSep = (char *) malloc(size);
     4379    rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
     4380    TRACE("Decimal Seperator is '%s'\n", decSep);
     4381
     4382    /* Now copy to temporary buffer, skipping any character except 0-9 and
     4383       the decimal seperator */
     4384    curPtr = pBuffer;      /* Current position in string being built       */
     4385    strPtr = pNewString;   /* Current position in supplied currenct string */
     4386
     4387    while (*strPtr) {
     4388        /* If decimal seperator, skip it and put '.' in string */
     4389        if (strncmp(strPtr, decSep, (size-1)) == 0) {
     4390            strPtr = strPtr + (size-1);
     4391            *curPtr = '.';
     4392            curPtr++;
     4393        } else if ((*strPtr == '+' || *strPtr == '-') ||
     4394                   (*strPtr >= '0' && *strPtr <= '9')) {
     4395            *curPtr = *strPtr;
     4396            strPtr++;
     4397            curPtr++;
     4398        } else strPtr++;
     4399    }
     4400    *curPtr = 0x00;
     4401
     4402    /* Try to get currency into a double */
     4403    currencyVal = atof(pBuffer);
     4404    TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
     4405
     4406    /* Free allocated storage */
     4407    HeapFree( GetProcessHeap(), 0, pNewString );
     4408    free(decSep);
     4409
     4410    /* Convert double -> currency using internal routine */
     4411        return VarCyFromR8(currencyVal, pcyOut);
     4412}
     4413
     4414
    42344415/**********************************************************************
    42354416 *              VarCyFromBool [OLEAUT32.106]
     
    42404421   else pcyOut->s.Hi = 0;
    42414422   pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
    4242    
     4423
    42434424   return S_OK;
    42444425}
     
    42524433   else pcyOut->s.Hi = 0;
    42534434   pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
    4254    
     4435
    42554436   return S_OK;
    42564437}
     
    42634444   pcyOut->s.Hi = 0;
    42644445   pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
    4265    
     4446
    42664447   return S_OK;
    42674448}
     
    42754456   pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
    42764457   pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
    4277      
     4458
    42784459   return S_OK;
    42794460}
     
    42914472
    42924473    TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
    4293    
     4474
    42944475    t.tm_sec = (wDosTime & 0x001f) * 2;
    42954476    t.tm_min = (wDosTime & 0x07e0) >> 5;
    42964477    t.tm_hour = (wDosTime & 0xf800) >> 11;
    4297    
     4478
    42984479    t.tm_mday = (wDosDate & 0x001f);
    42994480    t.tm_mon = (wDosDate & 0x01e0) >> 5;
     
    43124493    int i,lastent=0;
    43134494    int cDig;
     4495    BOOL foundNum=FALSE;
     4496
    43144497    FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
    43154498    FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
    43164499
    43174500    /* The other struct components are to be set by us */
    4318 
    43194501    memset(rgbDig,0,pnumprs->cDig);
     4502
     4503    /* FIXME: Just patching some values in */
     4504    pnumprs->nPwr10     = 0;
     4505    pnumprs->nBaseShift = 0;
     4506    pnumprs->cchUsed    = lastent;
     4507    pnumprs->dwOutFlags = NUMPRS_DECIMAL;
    43204508
    43214509    cDig = 0;
    43224510    for (i=0; strIn[i] ;i++) {
    43234511        if ((strIn[i]>='0') && (strIn[i]<='9')) {
     4512            foundNum = TRUE;
    43244513            if (pnumprs->cDig > cDig) {
    43254514                *(rgbDig++)=strIn[i]-'0';
     
    43274516                lastent = i;
    43284517            }
    4329         }
     4518        } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
     4519            pnumprs->dwOutFlags |= NUMPRS_NEG;
     4520        }
    43304521    }
    43314522    pnumprs->cDig       = cDig;
    4332 
    4333     /* FIXME: Just patching some values in */
    4334     pnumprs->nPwr10     = 0;
    4335     pnumprs->nBaseShift = 0;
    4336     pnumprs->cchUsed    = lastent;
    4337     pnumprs->dwOutFlags = NUMPRS_DECIMAL;
     4523    TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
    43384524    return S_OK;
    43394525}
     
    43484534    DWORD xint;
    43494535    int i;
    4350     FIXME("(,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
     4536    FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
    43514537
    43524538    xint = 0;
    43534539    for (i=0;i<pnumprs->cDig;i++)
    43544540        xint = xint*10 + rgbDig[i];
     4541
     4542    if (pnumprs->dwOutFlags & NUMPRS_NEG) {
     4543        xint = xint * -1;
     4544    }
    43554545
    43564546    VariantInit(pvar);
     
    43644554        V_UNION(pvar,dblVal) = xint;
    43654555        return S_OK;
    4366     } else {
    4367         FIXME("vtbitmask is unsupported %lx\n",dwVtBits);
     4556    }
     4557    if (dwVtBits & VTBIT_R4) {
     4558        V_VT(pvar) = VT_R4;
     4559        V_UNION(pvar,fltVal) = xint;
     4560        return S_OK;
     4561    }
     4562    if (dwVtBits & VTBIT_I2) {
     4563        V_VT(pvar) = VT_I2;
     4564        V_UNION(pvar,iVal) = xint;
     4565        return S_OK;
     4566    }
     4567    /* FIXME: Currency should be from a double */
     4568    if (dwVtBits & VTBIT_CY) {
     4569        V_VT(pvar) = VT_CY;
     4570        TRACE("Calculated currency is xint=%ld\n", xint);
     4571        VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
     4572        TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
     4573        return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
     4574    }
     4575
     4576        FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
    43684577        return E_FAIL;
    4369     }
    4370 }
    4371 
     4578}
     4579
     4580
     4581/**********************************************************************
     4582 *              VarFormatDateTime [OLEAUT32.97]
     4583 */
     4584HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
     4585{
     4586    FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
     4587    return E_NOTIMPL;
     4588}
     4589
     4590/**********************************************************************
     4591 *              VarFormatCurrency [OLEAUT32.127]
     4592 */
     4593HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
     4594{
     4595    FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
     4596    return E_NOTIMPL;
     4597}
    43724598
    43734599/**********************************************************************
     
    44034629HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME  lpSystemTime, double *pvtime )
    44044630{
    4405     static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    4406     static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    4407 
    44084631    struct tm t;
    44094632
     
    44204643
    44214644        t.tm_mday = lpSystemTime->wDay;
    4422         t.tm_mon = lpSystemTime->wMonth;
     4645        t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
    44234646        t.tm_year = lpSystemTime->wYear;
    44244647
     
    44274650    else
    44284651    {
     4652        double tmpDate;
     4653        long firstDayOfNextYear;
     4654        long thisDay;
     4655        long leftInYear;
     4656        long result;
     4657
     4658        double decimalPart = 0.0;
     4659
    44294660        t.tm_sec = lpSystemTime->wSecond;
    44304661        t.tm_min = lpSystemTime->wMinute;
    44314662        t.tm_hour = lpSystemTime->wHour;
    44324663
    4433         if (isleap(lpSystemTime->wYear) )
    4434             t.tm_mday = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - lpSystemTime->wDay;
    4435         else
    4436             t.tm_mday = Days_Per_Month[13 - lpSystemTime->wMonth] - lpSystemTime->wDay;
    4437 
    4438         t.tm_mon = 13 - lpSystemTime->wMonth;
     4664        /* Step year forward the same number of years before 1900 */
    44394665        t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
    4440 
     4666        t.tm_mon = lpSystemTime->wMonth - 1;
     4667        t.tm_mday = lpSystemTime->wDay;
     4668
     4669        /* Calculate date */
    44414670        TmToDATE( &t, pvtime );
    44424671
    4443         *pvtime *= -1;
     4672        thisDay = (double) floor( *pvtime );
     4673        decimalPart = fmod( *pvtime, thisDay );
     4674
     4675        /* Now, calculate the same time for the first of Jan that year */
     4676        t.tm_mon = 0;
     4677        t.tm_mday = 1;
     4678        t.tm_sec = 0;
     4679        t.tm_min = 0;
     4680        t.tm_hour = 0;
     4681        t.tm_year = t.tm_year+1;
     4682        TmToDATE( &t, &tmpDate );
     4683        firstDayOfNextYear = (long) floor(tmpDate);
     4684
     4685        /* Finally since we know the size of the year, subtract the two to get
     4686           remaining time in the year                                          */
     4687        leftInYear = firstDayOfNextYear - thisDay;
     4688
     4689        /* Now we want full years up to the year in question, and remainder of year
     4690           of the year in question */
     4691        if (isleap(lpSystemTime->wYear) ) {
     4692           TRACE("Extra day due to leap year\n");
     4693           result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
     4694        } else {
     4695           result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
     4696        }
     4697        *pvtime = (double) result + decimalPart;
     4698        TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
    44444699
    44454700        return 1;
     
    44684723    struct tm r;
    44694724
    4470     TRACE(" Variant = %f SYSTEMTIME ptr %p", vtime, lpSystemTime);
     4725    TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
    44714726
    44724727    if (vtime >= 0)
     
    46194874    *datein = t;
    46204875
    4621     if (i) dwFlags = 0; /*VAR_VALIDDATE*/
    4622     else dwFlags = 0;
    4623 
    4624     return i;
     4876    if (i) return S_OK;
     4877    else return E_INVALIDARG;
    46254878}
    46264879
    46274880
    46284881/**********************************************************************
    4629  *              VarBstrCmp [OLEAUT32.440]
     4882 *              VarBstrCmp [OLEAUT32.314]
    46304883 *
    4631  * flags can be: 
     4884 * flags can be:
    46324885 *   NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
    46334886 *   NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
     
    46364889HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
    46374890{
    4638     DWORD r;
    4639 
    4640     FIXME("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
    4641 
    4642     if((!left) || (!right))
    4643         return VARCMP_NULL;
     4891    INT r;
     4892
     4893    TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
     4894
     4895    /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
     4896    if((!left) || (!right)) {
     4897
     4898        if (!left && (!right || *right==0)) return VARCMP_EQ;
     4899        else if (!right && (!left || *left==0)) return VARCMP_EQ;
     4900        else return VARCMP_NULL;
     4901    }
    46444902
    46454903    if(flags&NORM_IGNORECASE)
     
    46574915
    46584916/**********************************************************************
    4659  *              VarBstrCat [OLEAUT32.439]
     4917 *              VarBstrCat [OLEAUT32.313]
    46604918 */
    46614919HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
    46624920{
    46634921    BSTR result;
     4922    int size = 0;
    46644923
    46654924    TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
    46664925
    4667     if( (!left) || (!right) || (!out) )
    4668         return 0;
    4669 
    4670     result = SysAllocStringLen(left, lstrlenW(left)+lstrlenW(right));
    4671     lstrcatW(result,right);
    4672 
    4673     *out = result;
    4674 
    4675     return 1;
     4926    /* On Windows, NULL parms are still handled (as empty strings) */
     4927    if (left)  size=size + lstrlenW(left);
     4928    if (right) size=size + lstrlenW(right);
     4929
     4930    if (out) {
     4931        result = SysAllocStringLen(NULL, size);
     4932        *out = result;
     4933        if (left) lstrcatW(result,left);
     4934        if (right) lstrcatW(result,right);
     4935        TRACE("result = %s, [%p]\n", debugstr_w(result), result);
     4936    }
     4937    return S_OK;
    46764938}
    46774939
    46784940/**********************************************************************
    4679  *              VarCat [OLEAUT32.441]
     4941 *              VarCat [OLEAUT32.318]
    46804942 */
    46814943HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
     
    46994961    return S_OK;
    47004962}
     4963
     4964/**********************************************************************
     4965 *              VarCmp [OLEAUT32.176]
     4966 *
     4967 * flags can be:
     4968 *   NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
     4969 *   NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
     4970 *
     4971 */
     4972HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
     4973{
     4974
     4975
     4976    BOOL         lOk        = TRUE;
     4977    BOOL         rOk        = TRUE;
     4978    LONGLONG     lVal = -1;
     4979    LONGLONG     rVal = -1;
     4980
     4981    TRACE("Left Var:\n");
     4982    dump_Variant(left);
     4983    TRACE("Right Var:\n");
     4984    dump_Variant(right);
     4985
     4986    /* If either are null, then return VARCMP_NULL */
     4987    if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
     4988        (V_VT(right)&VT_TYPEMASK) == VT_NULL)
     4989        return VARCMP_NULL;
     4990
     4991    /* Strings - use VarBstrCmp */
     4992    if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
     4993        (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
     4994        return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
     4995    }
     4996
     4997    /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
     4998           Use LONGLONG to maximize ranges                              */
     4999    lOk = TRUE;
     5000    switch (V_VT(left)&VT_TYPEMASK) {
     5001    case VT_I1   : lVal = V_UNION(left,cVal); break;
     5002    case VT_I2   : lVal = V_UNION(left,iVal); break;
     5003    case VT_I4   : lVal = V_UNION(left,lVal); break;
     5004    case VT_INT  : lVal = V_UNION(left,lVal); break;
     5005    case VT_UI1  : lVal = V_UNION(left,bVal); break;
     5006    case VT_UI2  : lVal = V_UNION(left,uiVal); break;
     5007    case VT_UI4  : lVal = V_UNION(left,ulVal); break;
     5008    case VT_UINT : lVal = V_UNION(left,ulVal); break;
     5009    default: lOk = FALSE;
     5010    }
     5011
     5012    rOk = TRUE;
     5013    switch (V_VT(right)&VT_TYPEMASK) {
     5014    case VT_I1   : rVal = V_UNION(right,cVal); break;
     5015    case VT_I2   : rVal = V_UNION(right,iVal); break;
     5016    case VT_I4   : rVal = V_UNION(right,lVal); break;
     5017    case VT_INT  : rVal = V_UNION(right,lVal); break;
     5018    case VT_UI1  : rVal = V_UNION(right,bVal); break;
     5019    case VT_UI2  : rVal = V_UNION(right,uiVal); break;
     5020    case VT_UI4  : rVal = V_UNION(right,ulVal); break;
     5021    case VT_UINT : rVal = V_UNION(right,ulVal); break;
     5022    default: rOk = FALSE;
     5023    }
     5024
     5025    if (lOk && rOk) {
     5026        if (lVal < rVal) {
     5027            return VARCMP_LT;
     5028        } else if (lVal > rVal) {
     5029            return VARCMP_GT;
     5030        } else {
     5031            return VARCMP_EQ;
     5032        }
     5033    }
     5034
     5035    /* Strings - use VarBstrCmp */
     5036    if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
     5037        (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
     5038
     5039        if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
     5040            /* Due to floating point rounding errors, calculate varDate in whole numbers) */
     5041            double wholePart = 0.0;
     5042            double leftR;
     5043            double rightR;
     5044
     5045            /* Get the fraction * 24*60*60 to make it into whole seconds */
     5046            wholePart = (double) floor( V_UNION(left,date) );
     5047            if (wholePart == 0) wholePart = 1;
     5048            leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
     5049
     5050            wholePart = (double) floor( V_UNION(right,date) );
     5051            if (wholePart == 0) wholePart = 1;
     5052            rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
     5053
     5054            if (leftR < rightR) {
     5055                return VARCMP_LT;
     5056            } else if (leftR > rightR) {
     5057                return VARCMP_GT;
     5058            } else {
     5059                return VARCMP_EQ;
     5060            }
     5061
     5062        } else if (V_UNION(left,date) < V_UNION(right,date)) {
     5063            return VARCMP_LT;
     5064        } else if (V_UNION(left,date) > V_UNION(right,date)) {
     5065            return VARCMP_GT;
     5066        }
     5067    }
     5068
     5069
     5070    FIXME("VarCmp partial implementation, doesnt support these pair of variant types");
     5071    return E_FAIL;
     5072}
     5073
     5074/**********************************************************************
     5075 *              VarAnd [OLEAUT32.142]
     5076 *
     5077 */
     5078HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
     5079{
     5080    HRESULT rc = E_FAIL;
     5081
     5082
     5083    TRACE("Left Var:\n");
     5084    dump_Variant(left);
     5085    TRACE("Right Var:\n");
     5086    dump_Variant(right);
     5087
     5088    if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
     5089        (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
     5090
     5091        V_VT(result) = VT_BOOL;
     5092        if (V_BOOL(left) && V_BOOL(right)) {
     5093            V_BOOL(result) = VARIANT_TRUE;
     5094        } else {
     5095            V_BOOL(result) = VARIANT_FALSE;
     5096        }
     5097        rc = S_OK;
     5098
     5099    } else {
     5100        FIXME("VarAnd stub\n");
     5101    }
     5102
     5103    TRACE("rc=%d, Result:\n", (int) rc);
     5104    dump_Variant(result);
     5105    return rc;
     5106}
     5107
     5108/**********************************************************************
     5109 *              VarNot [OLEAUT32.174]
     5110 *
     5111 */
     5112HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
     5113{
     5114    HRESULT rc = E_FAIL;
     5115
     5116    TRACE("Var In:\n");
     5117    dump_Variant(in);
     5118
     5119    if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
     5120
     5121        V_VT(result) = VT_BOOL;
     5122        if (V_BOOL(in)) {
     5123            V_BOOL(result) = VARIANT_FALSE;
     5124        } else {
     5125            V_BOOL(result) = VARIANT_TRUE;
     5126        }
     5127        rc = S_OK;
     5128
     5129    } else {
     5130        FIXME("VarNot stub\n");
     5131    }
     5132
     5133    TRACE("rc=%d, Result:\n", (int) rc);
     5134    dump_Variant(result);
     5135    return rc;
     5136}
     5137
     5138/**********************************************************************
     5139 *              VarTokenizeFormatString [OLEAUT32.140]
     5140 *
     5141 * From investigation on W2K, a list is built up which is:
     5142 *
     5143 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
     5144 * <token> - Insert appropriate token
     5145 *
     5146 */
     5147HRESULT WINAPI VarTokenizeFormatString(LPOLESTR  format, LPBYTE rgbTok,
     5148                     int   cbTok, int iFirstDay, int iFirstWeek,
     5149                     LCID  lcid, int *pcbActual) {
     5150
     5151    FORMATHDR *hdr;
     5152    int        realLen, formatLeft;
     5153    BYTE      *pData;
     5154    LPSTR      pFormatA, pStart;
     5155    int        checkStr;
     5156    BOOL       insertCopy = FALSE;
     5157    LPSTR      copyFrom = NULL;
     5158
     5159    TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
     5160                   iFirstDay, iFirstWeek);
     5161
     5162    /* Big enough for header? */
     5163    if (cbTok < sizeof(FORMATHDR)) {
     5164        return TYPE_E_BUFFERTOOSMALL;
     5165    }
     5166
     5167    /* Insert header */
     5168    hdr = (FORMATHDR *) rgbTok;
     5169    memset(hdr, 0x00, sizeof(FORMATHDR));
     5170    hdr->hex3 = 0x03; /* No idea what these are */
     5171    hdr->hex6 = 0x06;
     5172
     5173    /* Start parsing string */
     5174    realLen    = sizeof(FORMATHDR);
     5175    pData      = rgbTok + realLen;
     5176    pFormatA   = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
     5177    pStart     = pFormatA;
     5178    formatLeft = strlen(pFormatA);
     5179
     5180    /* Work through the format */
     5181    while (*pFormatA != 0x00) {
     5182
     5183        checkStr = 0;
     5184        while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
     5185            if (formatLeft >= formatTokens[checkStr].tokenSize &&
     5186                strncmp(formatTokens[checkStr].str, pFormatA,
     5187                        formatTokens[checkStr].tokenSize) == 0) {
     5188                TRACE("match on '%s'\n", formatTokens[checkStr].str);
     5189
     5190                /* Found Match! */
     5191
     5192                /* If we have skipped chars, insert the copy */
     5193                if (insertCopy == TRUE) {
     5194
     5195                    if ((realLen + 3) > cbTok) {
     5196                        HeapFree( GetProcessHeap(), 0, pFormatA );
     5197                        return TYPE_E_BUFFERTOOSMALL;
     5198                    }
     5199                    insertCopy = FALSE;
     5200                    *pData = TOK_COPY;
     5201                    pData++;
     5202                    *pData = (BYTE)(copyFrom - pStart);
     5203                    pData++;
     5204                    *pData = (BYTE)(pFormatA - copyFrom);
     5205                    pData++;
     5206                    realLen = realLen + 3;
     5207                }
     5208
     5209
     5210                /* Now insert the token itself */
     5211                if ((realLen + 1) > cbTok) {
     5212                    HeapFree( GetProcessHeap(), 0, pFormatA );
     5213                    return TYPE_E_BUFFERTOOSMALL;
     5214                }
     5215                *pData = formatTokens[checkStr].tokenId;
     5216                pData = pData + 1;
     5217                realLen = realLen + 1;
     5218
     5219                pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
     5220                formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
     5221                checkStr = -1; /* Flag as found and break out of while loop */
     5222            } else {
     5223                checkStr++;
     5224            }
     5225        }
     5226
     5227        /* Did we ever match a token? */
     5228        if (checkStr != -1 && insertCopy == FALSE) {
     5229            TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
     5230            insertCopy = TRUE;
     5231            copyFrom   = pFormatA;
     5232        } else if (checkStr != -1) {
     5233            pFormatA = pFormatA + 1;
     5234        }
     5235
     5236    }
     5237
     5238    /* Finally, if we have skipped chars, insert the copy */
     5239    if (insertCopy == TRUE) {
     5240
     5241        TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
     5242        if ((realLen + 3) > cbTok) {
     5243            HeapFree( GetProcessHeap(), 0, pFormatA );
     5244            return TYPE_E_BUFFERTOOSMALL;
     5245        }
     5246        insertCopy = FALSE;
     5247        *pData = TOK_COPY;
     5248        pData++;
     5249        *pData = (BYTE)(copyFrom - pStart);
     5250        pData++;
     5251        *pData = (BYTE)(pFormatA - copyFrom);
     5252        pData++;
     5253        realLen = realLen + 3;
     5254    }
     5255
     5256    /* Finally insert the terminator */
     5257    if ((realLen + 1) > cbTok) {
     5258        HeapFree( GetProcessHeap(), 0, pFormatA );
     5259        return TYPE_E_BUFFERTOOSMALL;
     5260    }
     5261    *pData++ = TOK_END;
     5262    realLen = realLen + 1;
     5263
     5264    /* Finally fill in the length */
     5265    hdr->len = realLen;
     5266    *pcbActual = realLen;
     5267
     5268#if 0
     5269    { int i,j;
     5270      for (i=0; i<realLen; i=i+0x10) {
     5271          printf(" %4.4x : ", i);
     5272          for (j=0; j<0x10 && (i+j < realLen); j++) {
     5273              printf("%2.2x ", rgbTok[i+j]);
     5274          }
     5275          printf("\n");
     5276      }
     5277    }
     5278#endif
     5279    HeapFree( GetProcessHeap(), 0, pFormatA );
     5280
     5281    return S_OK;
     5282}
     5283
     5284/**********************************************************************
     5285 *              VarFormatFromTokens [OLEAUT32.139]
     5286 * FIXME: No account of flags or iFirstDay etc
     5287 */
     5288HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
     5289                            LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
     5290                            LCID  lcid) {
     5291
     5292    FORMATHDR   *hdr = (FORMATHDR *)pbTokCur;
     5293    BYTE        *pData    = pbTokCur + sizeof (FORMATHDR);
     5294    LPSTR        pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
     5295    char         output[BUFFER_MAX];
     5296    char        *pNextPos;
     5297    int          size, whichToken;
     5298    VARIANTARG   Variant;
     5299    struct tm    TM;
     5300
     5301
     5302
     5303    TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
     5304    TRACE("varIn:\n");
     5305    dump_Variant(varIn);
     5306
     5307    memset(output, 0x00, BUFFER_MAX);
     5308    pNextPos = output;
     5309
     5310    while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
     5311
     5312        TRACE("Output looks like : '%s'\n", output);
     5313
     5314        /* Convert varient to appropriate data type */
     5315        whichToken = 0;
     5316        while ((formatTokens[whichToken].tokenSize != 0x00) &&
     5317               (formatTokens[whichToken].tokenId   != *pData)) {
     5318            whichToken++;
     5319        }
     5320
     5321        /* Use Variant local from here downwards as always correct type */
     5322        if (formatTokens[whichToken].tokenSize > 0 &&
     5323            formatTokens[whichToken].varTypeRequired != 0) {
     5324                        VariantInit( &Variant );
     5325            if (Coerce( &Variant, lcid, dwFlags, varIn,
     5326                        formatTokens[whichToken].varTypeRequired ) != S_OK) {
     5327                HeapFree( GetProcessHeap(), 0, pFormatA );
     5328                return DISP_E_TYPEMISMATCH;
     5329            } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
     5330                if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
     5331                    HeapFree( GetProcessHeap(), 0, pFormatA );
     5332                    return E_INVALIDARG;
     5333                }
     5334            }
     5335        }
     5336
     5337        TRACE("Looking for match on token '%x'\n", *pData);
     5338        switch (*pData) {
     5339        case TOK_COPY:
     5340            TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
     5341            memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
     5342            pNextPos = pNextPos + *(pData+2);
     5343            pData = pData + 3;
     5344            break;
     5345
     5346        case TOK_COLON   :
     5347            /* Get locale information - Time Seperator */
     5348            size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
     5349            GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
     5350            TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
     5351            pNextPos = pNextPos + size;
     5352            pData = pData + 1;
     5353            break;
     5354
     5355        case TOK_SLASH   :
     5356            /* Get locale information - Date Seperator */
     5357            size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
     5358            GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
     5359            TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
     5360            pNextPos = pNextPos + size;
     5361            pData = pData + 1;
     5362            break;
     5363
     5364        case TOK_d       :
     5365            sprintf(pNextPos, "%d", TM.tm_mday);
     5366            pNextPos = pNextPos + strlen(pNextPos);
     5367            pData = pData + 1;
     5368            break;
     5369
     5370        case TOK_dd      :
     5371            sprintf(pNextPos, "%2.2d", TM.tm_mday);
     5372            pNextPos = pNextPos + strlen(pNextPos);
     5373            pData = pData + 1;
     5374            break;
     5375
     5376        case TOK_w       :
     5377            sprintf(pNextPos, "%d", TM.tm_wday+1);
     5378            pNextPos = pNextPos + strlen(pNextPos);
     5379            pData = pData + 1;
     5380            break;
     5381
     5382        case TOK_m       :
     5383            sprintf(pNextPos, "%d", TM.tm_mon+1);
     5384            pNextPos = pNextPos + strlen(pNextPos);
     5385            pData = pData + 1;
     5386            break;
     5387
     5388        case TOK_mm      :
     5389            sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
     5390            pNextPos = pNextPos + strlen(pNextPos);
     5391            pData = pData + 1;
     5392            break;
     5393
     5394        case TOK_q       :
     5395            sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
     5396            pNextPos = pNextPos + strlen(pNextPos);
     5397            pData = pData + 1;
     5398            break;
     5399
     5400        case TOK_y       :
     5401            sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
     5402            pNextPos = pNextPos + strlen(pNextPos);
     5403            pData = pData + 1;
     5404            break;
     5405
     5406        case TOK_yy      :
     5407            sprintf(pNextPos, "%2.2d", TM.tm_year);
     5408            pNextPos = pNextPos + strlen(pNextPos);
     5409            pData = pData + 1;
     5410            break;
     5411
     5412        case TOK_yyyy    :
     5413            sprintf(pNextPos, "%4.4d", TM.tm_year);
     5414            pNextPos = pNextPos + strlen(pNextPos);
     5415            pData = pData + 1;
     5416            break;
     5417
     5418        case TOK_h       :
     5419            sprintf(pNextPos, "%d", TM.tm_hour);
     5420            pNextPos = pNextPos + strlen(pNextPos);
     5421            pData = pData + 1;
     5422            break;
     5423
     5424        case TOK_Hh      :
     5425            sprintf(pNextPos, "%2.2d", TM.tm_hour);
     5426            pNextPos = pNextPos + strlen(pNextPos);
     5427            pData = pData + 1;
     5428            break;
     5429
     5430        case TOK_N       :
     5431            sprintf(pNextPos, "%d", TM.tm_min);
     5432            pNextPos = pNextPos + strlen(pNextPos);
     5433            pData = pData + 1;
     5434            break;
     5435
     5436        case TOK_Nn      :
     5437            sprintf(pNextPos, "%2.2d", TM.tm_min);
     5438            pNextPos = pNextPos + strlen(pNextPos);
     5439            pData = pData + 1;
     5440            break;
     5441
     5442        case TOK_S       :
     5443            sprintf(pNextPos, "%d", TM.tm_sec);
     5444            pNextPos = pNextPos + strlen(pNextPos);
     5445            pData = pData + 1;
     5446            break;
     5447
     5448        case TOK_Ss      :
     5449            sprintf(pNextPos, "%2.2d", TM.tm_sec);
     5450            pNextPos = pNextPos + strlen(pNextPos);
     5451            pData = pData + 1;
     5452            break;
     5453
     5454        /* FIXME: To Do! */
     5455        case TOK_ttttt   :
     5456        case TOK_AMsPM   :
     5457        case TOK_amspm   :
     5458        case TOK_AsP     :
     5459        case TOK_asp     :
     5460        case TOK_AMPM    :
     5461        case TOK_c       :
     5462        case TOK_ddd     :
     5463        case TOK_dddd    :
     5464        case TOK_ddddd   :
     5465        case TOK_dddddd  :
     5466        case TOK_ww      :
     5467        case TOK_mmm     :
     5468        case TOK_mmmm    :
     5469        default:
     5470            FIXME("Unhandled token for VarFormat %d\n", *pData);
     5471            HeapFree( GetProcessHeap(), 0, pFormatA );
     5472            return E_INVALIDARG;
     5473        }
     5474
     5475    }
     5476
     5477    *pbstrOut = StringDupAtoBstr( output );
     5478    HeapFree( GetProcessHeap(), 0, pFormatA );
     5479    return S_OK;
     5480}
     5481
     5482/**********************************************************************
     5483 *              VarFormat [OLEAUT32.87]
     5484 *
     5485 */
     5486HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
     5487                         int firstDay, int firstWeek, ULONG dwFlags,
     5488                         BSTR *pbstrOut) {
     5489
     5490    LPSTR   pNewString = NULL;
     5491    HRESULT rc = S_OK;
     5492
     5493    TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
     5494          debugstr_w(format), firstDay, firstWeek, dwFlags);
     5495    TRACE("varIn:\n");
     5496    dump_Variant(varIn);
     5497
     5498    /* Note: Must Handle references type Variants (contain ptrs
     5499          to values rather than values */
     5500
     5501    /* Get format string */
     5502    pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
     5503
     5504    /* FIXME: Handle some simple pre-definted format strings : */
     5505    if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
     5506
     5507        /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
     5508        double curVal;
     5509
     5510
     5511        /* Handle references type Variants (contain ptrs to values rather than values */
     5512        if (V_VT(varIn)&VT_BYREF) {
     5513            rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
     5514        } else {
     5515            rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
     5516        }
     5517
     5518        if (rc == S_OK) {
     5519            char tmpStr[BUFFER_MAX];
     5520            sprintf(tmpStr, "%f", curVal);
     5521            if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
     5522                return E_FAIL;
     5523            } else {
     5524                *pbstrOut = StringDupAtoBstr( pBuffer );
     5525            }
     5526        }
     5527
     5528    } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
     5529
     5530        /* Attempt to do proper formatting! */
     5531        int firstToken = -1;
     5532
     5533        rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
     5534                                  firstWeek, GetUserDefaultLCID(), &firstToken);
     5535        if (rc==S_OK) {
     5536            rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
     5537        }
     5538
     5539    } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
     5540        if (V_VT(varIn)&VT_BYREF) {
     5541            sprintf(pBuffer, "%f", *(double *)V_UNION(varIn,byref));
     5542        } else {
     5543            sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
     5544        }
     5545
     5546        *pbstrOut = StringDupAtoBstr( pBuffer );
     5547
     5548    } else {
     5549        FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
     5550        *pbstrOut = StringDupAtoBstr( "??" );
     5551    }
     5552
     5553    /* Free allocated storage */
     5554    HeapFree( GetProcessHeap(), 0, pNewString );
     5555    TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
     5556    return rc;
     5557}
     5558
     5559/**********************************************************************
     5560 *              VarCyMulI4 [OLEAUT32.304]
     5561 * Multiply currency value by integer
     5562 */
     5563HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
     5564
     5565    double cyVal = 0;
     5566    HRESULT rc = S_OK;
     5567
     5568    rc = VarR8FromCy(cyIn, &cyVal);
     5569    if (rc == S_OK) {
     5570        rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
     5571        TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
     5572                    pcyOut->s.Hi, pcyOut->s.Lo);
     5573    }
     5574    return rc;
     5575}
Note: See TracChangeset for help on using the changeset viewer.