Changeset 10801 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Oct 9, 2005, 3:56:30 PM (20 years ago)
Author:
darin
Message:

JavaScriptCore:

Reviewed by Maciej; some changes done after review.

Retested all tests to be sure nothing broke; added layout test for bug 5280.

  • kjs/config.h: Removed TIME_WITH_SYS_TIME define. Also set HAVE_SYS_TIMEB_H for the APPLE case (the latter is accurate but irrelevant).
  • kjs/date_object.h: Reformatted. Removed unnecessary include of "function_object.h". Moved declarations of helper classes and functions into the cpp file.
  • kjs/date_object.cpp: Removed code at top to define macros to use CoreFoundation instead of POSIX date functions. (KJS::styleFromArgString): Tweaked to return early instead of using a variable. (KJS::formatLocaleDate): Tweaked to check for undefined rather than checking argument count. (KJS::formatDate): Made parameter const. (KJS::formatDateUTCVariant): Ditto. (KJS::formatTime): Ditto. (KJS::DateProtoFuncImp::callAsFunction): Use gmtime_r and localtime_r instead of gmtime and localtime. (KJS::DateObjectImp::callAsFunction): Use localtime_r instead of localtime. (KJS::ymdhmsToSeconds): Renamed from ymdhms_to_seconds. Changed computation to avoid possible overflow if year is an extremely large or small number. (KJS::makeTime): Removed code to move large month numbers from tm_mon to tm_year; this was to accomodate CFGregorianDate, which is no longer used (and didn't handle negative values). (KJS::parseDate): Renamed from KRFCDate_parseDate; changed to return a value in milliseconds rather than in seconds. Reformatted the code. Changed to use UTF8String() instead of ascii(), since ascii() is not thread safe. Changed some variables back from int to long to avoid trouble if the result of strtol does not fit in an int (64-bit issue only).

LayoutTests:

  • fast/js/date-negative-setmonth-expected.txt: Added.
  • fast/js/date-negative-setmonth.html: Added.
Location:
trunk/JavaScriptCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r10800 r10801  
     12005-10-09  Darin Adler  <[email protected]>
     2
     3        Reviewed by Maciej; some changes done after review.
     4
     5        - fixed http://bugzilla.opendarwin.org/show_bug.cgi?id=5280
     6          Date.setMonth fails with negative values
     7        - fixed http://bugzilla.opendarwin.org/show_bug.cgi?id=5154
     8          JSC should switch to _r variants of unix time/date functions
     9        - fixed a few possible overflow cases
     10
     11        Retested all tests to be sure nothing broke; added layout test for bug 5280.
     12
     13        * kjs/config.h: Removed TIME_WITH_SYS_TIME define. Also set HAVE_SYS_TIMEB_H
     14        for the __APPLE__ case (the latter is accurate but irrelevant).
     15
     16        * kjs/date_object.h: Reformatted. Removed unnecessary include of "function_object.h".
     17        Moved declarations of helper classes and functions into the cpp file.
     18
     19        * kjs/date_object.cpp: Removed code at top to define macros to use CoreFoundation instead of
     20        POSIX date functions.
     21        (KJS::styleFromArgString): Tweaked to return early instead of using a variable.
     22        (KJS::formatLocaleDate): Tweaked to check for undefined rather than checking argument count.
     23        (KJS::formatDate): Made parameter const.
     24        (KJS::formatDateUTCVariant): Ditto.
     25        (KJS::formatTime): Ditto.
     26        (KJS::DateProtoFuncImp::callAsFunction): Use gmtime_r and localtime_r instead of gmtime and
     27        localtime.
     28        (KJS::DateObjectImp::callAsFunction): Use localtime_r instead of localtime.
     29        (KJS::ymdhmsToSeconds): Renamed from ymdhms_to_seconds. Changed computation to avoid possible
     30        overflow if year is an extremely large or small number.
     31        (KJS::makeTime): Removed code to move large month numbers from tm_mon to tm_year; this was
     32        to accomodate CFGregorianDate, which is no longer used (and didn't handle negative values).
     33        (KJS::parseDate): Renamed from KRFCDate_parseDate; changed to return a value in milliseconds
     34        rather than in seconds. Reformatted the code. Changed to use UTF8String() instead of ascii(),
     35        since ascii() is not thread safe. Changed some variables back from int to long to avoid
     36        trouble if the result of strtol does not fit in an int (64-bit issue only).
     37
    1382005-10-08  Mitz Pettel  <[email protected]>
    239
  • trunk/JavaScriptCore/kjs/config.h

    r10798 r10801  
    99#define HAVE_SYS_PARAM_H 1
    1010#define HAVE_SYS_TIME_H 1
    11 #define TIME_WITH_SYS_TIME 1
     11#define HAVE_SYS_TIMEB_H 1
    1212
    1313#elif WIN32
     
    2727#define HAVE_SYS_PARAM_H 1
    2828#define HAVE_SYS_TIME_H 1
    29 #define TIME_WITH_SYS_TIME 1
    3029
    3130#endif
  • trunk/JavaScriptCore/kjs/date_object.cpp

    r10800 r10801  
    1 // -*- c-basic-offset: 2 -*-
    21/*
    32 *  This file is part of the KDE libraries
     
    2221
    2322#include "config.h"
    24 #ifndef HAVE_SYS_TIMEB_H
    25 #define HAVE_SYS_TIMEB_H 0
     23#include "date_object.h"
     24
     25#if HAVE_ERRNO_H
     26#include <errno.h>
    2627#endif
    2728
    28 #if TIME_WITH_SYS_TIME
    29 # include <sys/time.h>
    30 # include <time.h>
    31 #else
     29#if HAVE_SYS_PARAM_H
     30#include <sys/param.h>
     31#endif
     32
    3233#if HAVE_SYS_TIME_H
    3334#include <sys/time.h>
    34 #else
    35 #  include <time.h>
    36 # endif
    3735#endif
     36
    3837#if HAVE_SYS_TIMEB_H
    3938#include <sys/timeb.h>
    4039#endif
    4140
    42 #ifdef HAVE_ERRNO_H
    43 #include <errno.h>
    44 #endif
    45 
    46 #ifdef HAVE_SYS_PARAM_H
    47 #  include <sys/param.h>
    48 #endif // HAVE_SYS_PARAM_H
    49 
     41#include <ctype.h>
     42#include <float.h>
     43#include <limits.h>
     44#include <locale.h>
    5045#include <math.h>
    51 #include <string.h>
    5246#include <stdio.h>
    5347#include <stdlib.h>
    54 #include <locale.h>
    55 #include <ctype.h>
    56 #include <limits.h>
    57 
    58 #include "date_object.h"
     48#include <string.h>
     49#include <time.h>
     50
    5951#include "error_object.h"
    6052#include "operations.h"
    6153
     54#if __APPLE__
     55#include <CoreFoundation/CoreFoundation.h>
     56#endif
     57
    6258#if WIN32
     59#define copysign(x, y) _copysign(x, y)
     60#define isfinite(x) _finite(x)
    6361#define strncasecmp(x, y, z) strnicmp(x, y, z)
    64 #include <float.h>
    65 #define isfinite(x) _finite(x)
    66 #define copysign(x, y) _copysign(x, y)
    6762#endif
    6863
     64namespace KJS {
     65
     66/**
     67 * @internal
     68 *
     69 * Class to implement all methods that are properties of the
     70 * Date.prototype object
     71 */
     72class DateProtoFuncImp : public InternalFunctionImp {
     73public:
     74    DateProtoFuncImp(ExecState *, int i, int len);
     75
     76    virtual bool implementsCall() const;
     77    virtual ValueImp *callAsFunction(ExecState *, ObjectImp *thisObj, const List &args);
     78
     79    Completion execute(const List &);
     80    enum { ToString, ToDateString, ToTimeString, ToLocaleString,
     81           ToLocaleDateString, ToLocaleTimeString, ValueOf, GetTime,
     82           GetFullYear, GetMonth, GetDate, GetDay, GetHours, GetMinutes,
     83           GetSeconds, GetMilliSeconds, GetTimezoneOffset, SetTime,
     84           SetMilliSeconds, SetSeconds, SetMinutes, SetHours, SetDate,
     85           SetMonth, SetFullYear, ToUTCString,
     86           // non-normative properties (Appendix B)
     87           GetYear, SetYear, ToGMTString };
     88private:
     89    int id;
     90    bool utc;
     91};
     92
     93/**
     94 * @internal
     95 *
     96 * Class to implement all methods that are properties of the
     97 * Date object
     98 */
     99class DateObjectFuncImp : public InternalFunctionImp {
     100public:
     101    DateObjectFuncImp(ExecState *, FunctionPrototypeImp *, int i, int len);
     102
     103    virtual bool implementsCall() const;
     104    virtual ValueImp *callAsFunction(ExecState *, ObjectImp *thisObj, const List &args);
     105
     106    enum { Parse, UTC };
     107
     108private:
     109    int id;
     110};
     111
     112}
     113
    69114#include "date_object.lut.h"
    70115
     116namespace KJS {
     117
    71118// some constants
    72 const time_t invalidDate = LONG_MIN;
    73119const double hoursPerDay = 24;
    74120const double minutesPerHour = 60;
     
    81127static const char * const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
    82128   
    83 #ifdef APPLE_CHANGES
    84 
    85 // Originally, we wrote our own implementation that uses Core Foundation because of a performance problem in Mac OS X 10.2.
    86 // But we need to keep using this rather than the standard library functions because this handles a larger range of dates.
    87 
    88 #include <notify.h>
    89 #include <CoreFoundation/CoreFoundation.h>
    90 #include <CoreServices/CoreServices.h>
    91 
    92 using KJS::UChar;
    93 using KJS::UString;
    94 
    95 #define gmtime(x) gmtimeUsingCF(x)
    96 #define localtime(x) localtimeUsingCF(x)
    97 #define mktime(x) mktimeUsingCF(x)
    98 #define time(x) timeUsingCF(x)
    99 
    100 #define ctime(x) NotAllowedToCallThis()
    101 #define strftime(a, b, c, d) NotAllowedToCallThis()
    102 
    103 static struct tm *tmUsingCF(time_t clock, CFTimeZoneRef timeZone)
    104 {
    105     static struct tm result;
    106     static char timeZoneCString[128];
    107    
    108     CFAbsoluteTime absoluteTime = clock - kCFAbsoluteTimeIntervalSince1970;
    109     CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(absoluteTime, timeZone);
    110 
    111     CFStringRef abbreviation = CFTimeZoneCopyAbbreviation(timeZone, absoluteTime);
    112     CFStringGetCString(abbreviation, timeZoneCString, sizeof(timeZoneCString), kCFStringEncodingASCII);
    113     CFRelease(abbreviation);
    114 
    115     result.tm_sec = (int)date.second;
    116     result.tm_min = date.minute;
    117     result.tm_hour = date.hour;
    118     result.tm_mday = date.day;
    119     result.tm_mon = date.month - 1;
    120     result.tm_year = date.year - 1900;
    121     result.tm_wday = CFAbsoluteTimeGetDayOfWeek(absoluteTime, timeZone) % 7;
    122     result.tm_yday = CFAbsoluteTimeGetDayOfYear(absoluteTime, timeZone) - 1;
    123     result.tm_isdst = CFTimeZoneIsDaylightSavingTime(timeZone, absoluteTime);
    124     result.tm_gmtoff = (int)CFTimeZoneGetSecondsFromGMT(timeZone, absoluteTime);
    125     result.tm_zone = timeZoneCString;
    126    
    127     return &result;
    128 }
    129 
    130 static CFTimeZoneRef UTCTimeZone()
    131 {
    132     static CFTimeZoneRef zone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0.0);
    133     return zone;
    134 }
    135 
    136 static CFTimeZoneRef CopyLocalTimeZone()
    137 {
    138     // Check for a time zone notification, and tell CoreFoundation to re-get the time zone if it happened.
    139     // Some day, CoreFoundation may do this itself, but for now it needs our help.
    140     static bool registered = false;
    141     static int notificationToken;
    142     if (!registered) {
    143         uint32_t status = notify_register_check("com.apple.system.timezone", &notificationToken);
    144         if (status == NOTIFY_STATUS_OK) {
    145             registered = true;
    146         }
    147     }
    148     if (registered) {
    149         int notified;
    150         uint32_t status = notify_check(notificationToken, &notified);
    151         if (status == NOTIFY_STATUS_OK && notified) {
    152             CFTimeZoneResetSystem();
    153         }
    154     }
    155 
    156     CFTimeZoneRef zone = CFTimeZoneCopyDefault();
    157     if (zone) {
    158         return zone;
    159     }
    160     zone = UTCTimeZone();
    161     CFRetain(zone);
    162     return zone;
    163 }
    164 
    165 static struct tm *gmtimeUsingCF(const time_t *clock)
    166 {
    167     return tmUsingCF(*clock, UTCTimeZone());
    168 }
    169 
    170 static struct tm *localtimeUsingCF(const time_t *clock)
    171 {
    172     CFTimeZoneRef timeZone = CopyLocalTimeZone();
    173     struct tm *result = tmUsingCF(*clock, timeZone);
    174     CFRelease(timeZone);
    175     return result;
    176 }
    177 
    178 static time_t timetUsingCF(struct tm *tm, CFTimeZoneRef timeZone)
    179 {
    180     CFGregorianDate date;
    181     date.second = tm->tm_sec;
    182     date.minute = tm->tm_min;
    183     date.hour = tm->tm_hour;
    184     date.day = tm->tm_mday;
    185     date.month = tm->tm_mon + 1;
    186     date.year = tm->tm_year + 1900;
    187 
    188     // CFGregorianDateGetAbsoluteTime will go nuts if the year is too large or small,
    189     // so we pick an arbitrary cutoff.
    190     if (date.year < -2500 || date.year > 2500) {
    191         return invalidDate;
    192     }
    193 
    194     CFAbsoluteTime absoluteTime = CFGregorianDateGetAbsoluteTime(date, timeZone);
    195 
    196     if (tm->tm_isdst >= 0) {
    197       if (CFTimeZoneIsDaylightSavingTime(timeZone, absoluteTime) && !tm->tm_isdst)
    198         absoluteTime += 3600;
    199       else if (!CFTimeZoneIsDaylightSavingTime(timeZone, absoluteTime) && tm->tm_isdst)
    200         absoluteTime -= 3600;
    201     }
    202 
    203     CFTimeInterval interval = absoluteTime + kCFAbsoluteTimeIntervalSince1970;
    204     if (interval > LONG_MAX) {
    205         return invalidDate;
    206     }
    207 
    208     return (time_t) interval;
    209 }
    210 
    211 static time_t mktimeUsingCF(struct tm *tm)
    212 {
    213     CFTimeZoneRef timeZone = CopyLocalTimeZone();
    214     time_t result = timetUsingCF(tm, timeZone);
    215     CFRelease(timeZone);
    216     return result;
    217 }
    218 
    219 static time_t timeUsingCF(time_t *clock)
    220 {
    221     time_t result = (time_t)(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970);
    222     if (clock) {
    223         *clock = result;
    224     }
    225     return result;
    226 }
    227 
    228 static CFDateFormatterStyle styleFromArgString(const UString& string,CFDateFormatterStyle defaultStyle)
    229 {
    230     CFDateFormatterStyle retVal = defaultStyle;
     129static double makeTime(tm *, double ms, bool utc);
     130static double parseDate(const UString &);
     131static double timeClip(double);
     132
     133#if __APPLE__
     134
     135static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
     136{
    231137    if (string == "short")
    232         retVal = kCFDateFormatterShortStyle;
    233     else if (string == "medium")
    234         retVal = kCFDateFormatterMediumStyle;
    235     else if (string == "long")
    236         retVal = kCFDateFormatterLongStyle;
    237     else if (string == "full")
    238         retVal = kCFDateFormatterFullStyle;
    239     return retVal;
    240 }
    241 
    242 static UString formatLocaleDate(KJS::ExecState *exec, double time, bool includeDate, bool includeTime, const KJS::List &args)
    243 {
    244     CFLocaleRef locale = CFLocaleCopyCurrent();
    245     int argCount = args.size();
    246    
    247     CFDateFormatterStyle    dateStyle = (includeDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
    248     CFDateFormatterStyle    timeStyle = (includeTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
    249 
    250     UString     arg0String;
    251     UString     arg1String;
    252     bool        useCustomFormat = false;
    253     UString     customFormatString;
    254     arg0String = args[0]->toString(exec);
    255     if ((arg0String == "custom") && (argCount >= 2)) {
     138        return kCFDateFormatterShortStyle;
     139    if (string == "medium")
     140        return kCFDateFormatterMediumStyle;
     141    if (string == "long")
     142        return kCFDateFormatterLongStyle;
     143    if (string == "full")
     144        return kCFDateFormatterFullStyle;
     145    return defaultStyle;
     146}
     147
     148static UString formatLocaleDate(ExecState *exec, double time, bool includeDate, bool includeTime, const List &args)
     149{
     150    CFDateFormatterStyle dateStyle = (includeDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
     151    CFDateFormatterStyle timeStyle = (includeTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
     152
     153    bool useCustomFormat = false;
     154    UString customFormatString;
     155
     156    UString arg0String = args[0]->toString(exec);
     157    if (arg0String == "custom" && !args[1]->isUndefined()) {
    256158        useCustomFormat = true;
    257159        customFormatString = args[1]->toString(exec);
    258     } else if (includeDate && includeTime && (argCount >= 2)) {
    259         arg1String = args[1]->toString(exec);
    260         dateStyle = styleFromArgString(arg0String,dateStyle);
    261         timeStyle = styleFromArgString(arg1String,timeStyle);
    262     } else if (includeDate && (argCount >= 1)) {
    263         dateStyle = styleFromArgString(arg0String,dateStyle);
    264     } else if (includeTime && (argCount >= 1)) {
    265         timeStyle = styleFromArgString(arg0String,timeStyle);
    266     }
    267     CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, dateStyle, timeStyle);
     160    } else if (includeDate && includeTime && !args[1]->isUndefined()) {
     161        dateStyle = styleFromArgString(arg0String, dateStyle);
     162        timeStyle = styleFromArgString(args[1]->toString(exec), timeStyle);
     163    } else if (includeDate && !args[0]->isUndefined()) {
     164        dateStyle = styleFromArgString(arg0String, dateStyle);
     165    } else if (includeTime && !args[0]->isUndefined()) {
     166        timeStyle = styleFromArgString(arg0String, timeStyle);
     167    }
     168
     169    CFLocaleRef locale = CFLocaleCopyCurrent();
     170    CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
     171    CFRelease(locale);
     172
    268173    if (useCustomFormat) {
    269         CFStringRef     customFormatCFString = CFStringCreateWithCharacters(NULL,(UniChar*)customFormatString.data(),customFormatString.size());
    270         CFDateFormatterSetFormat(formatter,customFormatCFString);
     174        CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, (UniChar *)customFormatString.data(), customFormatString.size());
     175        CFDateFormatterSetFormat(formatter, customFormatCFString);
    271176        CFRelease(customFormatCFString);
    272177    }
    273     CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(NULL, formatter, time - kCFAbsoluteTimeIntervalSince1970);
     178
     179    CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, time - kCFAbsoluteTimeIntervalSince1970);
     180
     181    CFRelease(formatter);
     182
    274183    // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
    275184    // That's not great error handling, but it just won't happen so it doesn't matter.
     
    283192
    284193    CFRelease(string);
    285     CFRelease(formatter);
    286     CFRelease(locale);
    287    
     194
    288195    return UString(buffer, length);
    289196}
    290197
    291 #endif // APPLE_CHANGES
    292 
    293 namespace KJS {
    294 
    295 static UString formatDate(struct tm &tm)
     198#endif // __APPLE__
     199
     200static UString formatDate(const tm &t)
    296201{
    297202    char buffer[100];
    298203    snprintf(buffer, sizeof(buffer), "%s %s %02d %04d",
    299         weekdayName[(tm.tm_wday + 6) % 7],
    300         monthName[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900);
     204        weekdayName[(t.tm_wday + 6) % 7],
     205        monthName[t.tm_mon], t.tm_mday, t.tm_year + 1900);
    301206    return buffer;
    302207}
    303208
    304 static UString formatDateUTCVariant(struct tm &tm)
     209static UString formatDateUTCVariant(const tm &t)
    305210{
    306211    char buffer[100];
    307212    snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d",
    308         weekdayName[(tm.tm_wday + 6) % 7],
    309         tm.tm_mday, monthName[tm.tm_mon], tm.tm_year + 1900);
     213        weekdayName[(t.tm_wday + 6) % 7],
     214        t.tm_mday, monthName[t.tm_mon], t.tm_year + 1900);
    310215    return buffer;
    311216}
    312217
    313 static UString formatTime(struct tm &tm)
     218static UString formatTime(const tm &t)
    314219{
    315220    char buffer[100];
    316     if (tm.tm_gmtoff == 0) {
    317         snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", tm.tm_hour, tm.tm_min, tm.tm_sec);
     221    if (t.tm_gmtoff == 0) {
     222        snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.tm_hour, t.tm_min, t.tm_sec);
    318223    } else {
    319         int offset = tm.tm_gmtoff;
    320         if (offset < 0) {
    321             offset = -offset;
    322         }
     224        int offset = abs(t.tm_gmtoff);
    323225        snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d",
    324             tm.tm_hour, tm.tm_min, tm.tm_sec,
    325             tm.tm_gmtoff < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60);
     226            t.tm_hour, t.tm_min, t.tm_sec,
     227            t.tm_gmtoff < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60);
    326228    }
    327229    return UString(buffer);
     
    330232static int day(double t)
    331233{
    332   return int(floor(t / msPerDay));
     234    return int(floor(t / msPerDay));
    333235}
    334236
    335237static double dayFromYear(int year)
    336238{
    337   return 365.0 * (year - 1970)
    338     + floor((year - 1969) / 4.0)
    339     - floor((year - 1901) / 100.0)
    340     + floor((year - 1601) / 400.0);
    341 }
    342 
    343 // depending on whether it's a leap year or not
     239    return 365.0 * (year - 1970)
     240        + floor((year - 1969) / 4.0)
     241        - floor((year - 1901) / 100.0)
     242        + floor((year - 1601) / 400.0);
     243}
     244
     245// based on the rule for whether it's a leap year or not
    344246static int daysInYear(int year)
    345247{
    346   if (year % 4 != 0)
    347     return 365;
    348   else if (year % 400 == 0)
    349     return 366;
    350   else if (year % 100 == 0)
    351     return 365;
    352   else
     248    if (year % 4 != 0)
     249        return 365;
     250    if (year % 400 == 0)
     251        return 366;
     252    if (year % 100 == 0)
     253        return 365;
    353254    return 366;
    354255}
     
    357258static double timeFromYear(int year)
    358259{
    359   return msPerDay * dayFromYear(year);
     260    return msPerDay * dayFromYear(year);
    360261}
    361262
     
    363264static int yearFromTime(double t)
    364265{
    365   // ### there must be an easier way
    366   // initial guess
    367   int y = 1970 + int(t / (365.25 * msPerDay));
    368   // adjustment
    369   if (timeFromYear(y) > t) {
    370     do {
    371       --y;
    372     } while (timeFromYear(y) > t);
    373   } else {
    374     while (timeFromYear(y + 1) < t)
    375       ++y;
    376   }
    377 
    378   return y;
     266    // ### there must be an easier way
     267
     268    // initial guess
     269    int y = 1970 + int(t / (365.25 * msPerDay));
     270
     271    // adjustment
     272    if (timeFromYear(y) > t) {
     273        do
     274            --y;
     275        while (timeFromYear(y) > t);
     276    } else {
     277        while (timeFromYear(y + 1) < t)
     278            ++y;
     279    }
     280
     281    return y;
    379282}
    380283
     
    382285static int weekDay(double t)
    383286{
    384   int wd = (day(t) + 4) % 7;
    385   if (wd < 0)
    386     wd += 7;
    387   return wd;
    388 }
    389 
    390 static long timeZoneOffset(const struct tm *t)
    391 {
    392 #if !defined(WIN32)
    393   return -(t->tm_gmtoff / 60);
     287    int wd = (day(t) + 4) % 7;
     288    if (wd < 0)
     289        wd += 7;
     290    return wd;
     291}
     292
     293static long timeZoneOffset(const tm &t)
     294{
     295#if !WIN32
     296    return -(t.tm_gmtoff / 60);
    394297#else
    395 #  if defined(__BORLANDC__) || defined(__CYGWIN__)
    396 // FIXME consider non one-hour DST change
    397 #if !defined(__CYGWIN__)
    398 #error please add daylight savings offset here!
    399 #endif
    400   return _timezone / 60 - (t->tm_isdst > 0 ? 60 : 0);
     298#  if __BORLANDC__ || __CYGWIN__
     299// FIXME: Can't be right because time zone is supposed to be from the parameter, not the computer.
     300// FIXME: consider non one-hour DST change.
     301#    if !__CYGWIN__
     302#      error please add daylight savings offset here!
     303#    endif
     304    return _timezone / 60 - (t.tm_isdst > 0 ? 60 : 0);
    401305#  else
    402   return timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 );
     306    return timezone / 60 - (t.tm_isdst > 0 ? 60 : 0 );
    403307#  endif
    404308#endif
     
    409313//
    410314// Format of member function: f([hour,] [min,] [sec,] [ms])
    411 static void fillStructuresUsingTimeArgs(ExecState *exec, const List &args, int maxArgs, double *ms, struct tm *t)
     315static void fillStructuresUsingTimeArgs(ExecState *exec, const List &args, int maxArgs, double *ms, tm *t)
    412316{
    413317    double milliseconds = 0;
     
    451355//
    452356// Format of member function: f([years,] [months,] [days])
    453 static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, struct tm *t)
    454 {
    455   int idx = 0;
    456   int numArgs = args.size();
     357static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, tm *t)
     358{
     359    int idx = 0;
     360    int numArgs = args.size();
    457361 
    458   // JS allows extra trailing arguments -- ignore them
    459   if (numArgs > maxArgs)
    460     numArgs = maxArgs;
     362    // JS allows extra trailing arguments -- ignore them
     363    if (numArgs > maxArgs)
     364        numArgs = maxArgs;
    461365 
    462   // years
    463   if (maxArgs >= 3 && idx < numArgs) {
    464     t->tm_year = args[idx++]->toInt32(exec) - 1900;
    465   }
     366    // years
     367    if (maxArgs >= 3 && idx < numArgs)
     368        t->tm_year = args[idx++]->toInt32(exec) - 1900;
    466369 
    467   // months
    468   if (maxArgs >= 2 && idx < numArgs) {
    469     t->tm_mon = args[idx++]->toInt32(exec);
    470   }
     370    // months
     371    if (maxArgs >= 2 && idx < numArgs)
     372        t->tm_mon = args[idx++]->toInt32(exec);
    471373 
    472   // days
    473   if (idx < numArgs) {
    474     t->tm_mday = 0;
    475     *ms += args[idx]->toInt32(exec) * msPerDay;
    476   }
     374    // days
     375    if (idx < numArgs) {
     376        t->tm_mday = 0;
     377        *ms += args[idx]->toInt32(exec) * msPerDay;
     378    }
    477379}
    478380
     
    541443// ECMA 15.9.4
    542444
    543 DatePrototypeImp::DatePrototypeImp(ExecState *,
    544                                    ObjectPrototypeImp *objectProto)
     445DatePrototypeImp::DatePrototypeImp(ExecState *, ObjectPrototypeImp *objectProto)
    545446  : DateInstanceImp(objectProto)
    546447{
    547   setInternalValue(jsNaN());
    548   // The constructor will be added later, after DateObjectImp has been built
     448    setInternalValue(jsNaN());
     449    // The constructor will be added later, after DateObjectImp has been built.
    549450}
    550451
    551452bool DatePrototypeImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
    552453{
    553   return getStaticFunctionSlot<DateProtoFuncImp, ObjectImp>(exec, &dateTable, this, propertyName, slot);
     454    return getStaticFunctionSlot<DateProtoFuncImp, ObjectImp>(exec, &dateTable, this, propertyName, slot);
    554455}
    555456
     
    557458
    558459DateProtoFuncImp::DateProtoFuncImp(ExecState *exec, int i, int len)
    559   : InternalFunctionImp(
    560     static_cast<FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype())
    561     ), id(abs(i)), utc(i<0)
     460  : InternalFunctionImp(static_cast<FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype())),
     461    id(abs(i)), utc(i<0)
    562462  // We use a negative ID to denote the "UTC" variant.
    563463{
    564   putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
     464    putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
    565465}
    566466
    567467bool DateProtoFuncImp::implementsCall() const
    568468{
    569   return true;
     469    return true;
    570470}
    571471
     
    582482
    583483
    584   ValueImp *result = NULL;
     484  ValueImp *result = 0;
    585485  UString s;
    586 #if !defined(APPLE_CHANGES) || !APPLE_CHANGES
     486#if !__APPLE__
    587487  const int bufsize=100;
    588488  char timebuffer[bufsize];
    589   CString oldlocale = setlocale(LC_TIME,NULL);
     489  CString oldlocale = setlocale(LC_TIME, 0);
    590490  if (!oldlocale.c_str())
    591     oldlocale = setlocale(LC_ALL, NULL);
     491    oldlocale = setlocale(LC_ALL, 0);
     492  // FIXME: Where's the code to set the locale back to oldlocale?
    592493#endif
    593494  ValueImp *v = thisObj->internalValue();
     
    603504      case ToLocaleDateString:
    604505      case ToLocaleTimeString:
    605         return String("Invalid Date");
     506        return jsString("Invalid Date");
    606507      case ValueOf:
    607508      case GetTime:
     
    624525  int realYearOffset = 0;
    625526  double milliOffset = 0.0;
    626   double secs = floor(milli / 1000.0);
     527  double secs = floor(milli / msPerSecond);
    627528
    628529  if (milli < 0 || milli >= timeFromYear(2038)) {
     
    635536  }
    636537
    637   time_t tv = (time_t) floor(milli / 1000.0);
    638   double ms = milli - tv * 1000.0;
    639 
    640   // FIXME: not threadsafe (either of these options)
    641   struct tm *t = utc ? gmtime(&tv) : localtime(&tv);
    642   // we had an out of range year. use that one (plus/minus offset
    643   // found by calculating tm_year) and fix the week day calculation
     538  time_t tv = (time_t) floor(milli / msPerSecond);
     539  double ms = milli - tv * msPerSecond;
     540
     541  tm t;
     542  utc ? gmtime_r(&tv, &t) : localtime_r(&tv, &t);
     543  // We had an out of range year. Restore the year (plus/minus offset
     544  // found by calculating tm_year) and fix the week day calculation.
    644545  if (realYearOffset != 0) {
    645     t->tm_year += realYearOffset;
     546    t.tm_year += realYearOffset;
    646547    milli -= milliOffset;
    647     // our own weekday calculation. beware of need for local time.
     548    // Do our own weekday calculation. Use time zone offset to handle local time.
    648549    double m = milli;
    649550    if (!utc)
    650551      m -= timeZoneOffset(t) * msPerMinute;
    651     t->tm_wday = weekDay(m);
     552    t.tm_wday = weekDay(m);
    652553  }
    653  
     554
    654555  switch (id) {
    655556  case ToString:
    656     result = String(formatDate(*t) + " " + formatTime(*t));
    657     break;
     557    return jsString(formatDate(t) + " " + formatTime(t));
    658558  case ToDateString:
    659     result = String(formatDate(*t));
     559    return jsString(formatDate(t));
    660560    break;
    661561  case ToTimeString:
    662     result = String(formatTime(*t));
     562    return jsString(formatTime(t));
    663563    break;
    664564  case ToGMTString:
    665565  case ToUTCString:
    666     result = String(formatDateUTCVariant(*t) + " " + formatTime(*t));
    667     break;
    668 #if APPLE_CHANGES
     566    return jsString(formatDateUTCVariant(t) + " " + formatTime(t));
     567    break;
     568#if __APPLE__
    669569  case ToLocaleString:
    670     result = String(formatLocaleDate(exec, secs, true, true, args));
     570    return jsString(formatLocaleDate(exec, secs, true, true, args));
    671571    break;
    672572  case ToLocaleDateString:
    673     result = String(formatLocaleDate(exec, secs, true, false, args));
     573    return jsString(formatLocaleDate(exec, secs, true, false, args));
    674574    break;
    675575  case ToLocaleTimeString:
    676     result = String(formatLocaleDate(exec, secs, false, true, args));
     576    return jsString(formatLocaleDate(exec, secs, false, true, args));
    677577    break;
    678578#else
    679579  case ToLocaleString:
    680580    strftime(timebuffer, bufsize, "%c", t);
    681     result = String(timebuffer);
     581    return jsString(timebuffer);
    682582    break;
    683583  case ToLocaleDateString:
    684584    strftime(timebuffer, bufsize, "%x", t);
    685     result = String(timebuffer);
     585    return jsString(timebuffer);
    686586    break;
    687587  case ToLocaleTimeString:
    688588    strftime(timebuffer, bufsize, "%X", t);
    689     result = String(timebuffer);
     589    return jsString(timebuffer);
    690590    break;
    691591#endif
    692592  case ValueOf:
    693     result = Number(milli);
    694     break;
    695593  case GetTime:
    696     result = Number(milli);
    697     break;
     594    return jsNumber(milli);
    698595  case GetYear:
    699596    // IE returns the full year even in getYear.
    700     if ( exec->dynamicInterpreter()->compatMode() == Interpreter::IECompat )
    701       result = Number(1900 + t->tm_year);
    702     else
    703       result = Number(t->tm_year);
    704     break;
     597    if (exec->dynamicInterpreter()->compatMode() == Interpreter::IECompat)
     598      return jsNumber(1900 + t.tm_year);
     599    return jsNumber(t.tm_year);
    705600  case GetFullYear:
    706     result = Number(1900 + t->tm_year);
    707     break;
     601    return jsNumber(1900 + t.tm_year);
    708602  case GetMonth:
    709     result = Number(t->tm_mon);
    710     break;
     603    return jsNumber(t.tm_mon);
    711604  case GetDate:
    712     result = Number(t->tm_mday);
    713     break;
     605    return jsNumber(t.tm_mday);
    714606  case GetDay:
    715     result = Number(t->tm_wday);
    716     break;
     607    return jsNumber(t.tm_wday);
    717608  case GetHours:
    718     result = Number(t->tm_hour);
    719     break;
     609    return jsNumber(t.tm_hour);
    720610  case GetMinutes:
    721     result = Number(t->tm_min);
    722     break;
     611    return jsNumber(t.tm_min);
    723612  case GetSeconds:
    724     result = Number(t->tm_sec);
    725     break;
     613    return jsNumber(t.tm_sec);
    726614  case GetMilliSeconds:
    727     result = Number(ms);
    728     break;
     615    return jsNumber(ms);
    729616  case GetTimezoneOffset:
    730 #if WIN32
    731 #  if defined(__BORLANDC__)
     617#if !WIN32
     618    return jsNumber(-t.tm_gmtoff / 60);
     619#else
     620#  if __BORLANDC__
    732621#error please add daylight savings offset here!
    733622    // FIXME: Using the daylight value was wrong for BSD, maybe wrong here too.
    734     result = Number(_timezone / 60 - (_daylight ? 60 : 0));
     623    return jsNumber(_timezone / 60 - (_daylight ? 60 : 0));
    735624#  else
    736625    // FIXME: Using the daylight value was wrong for BSD, maybe wrong here too.
    737     result = Number(( timezone / 60 - ( daylight ? 60 : 0 )));
     626    return jsNumber(( timezone / 60 - (daylight ? 60 : 0 )));
    738627#  endif
    739 #else
    740     result = Number(-t->tm_gmtoff / 60);
    741628#endif
    742     break;
    743629  case SetTime:
    744630    milli = roundValue(exec, args[0]);
    745     result = Number(milli);
     631    result = jsNumber(milli);
    746632    thisObj->setInternalValue(result);
    747633    break;
    748634  case SetMilliSeconds:
    749     fillStructuresUsingTimeArgs(exec, args, 1, &ms, t);
     635    fillStructuresUsingTimeArgs(exec, args, 1, &ms, &t);
    750636    break;
    751637  case SetSeconds:
    752     fillStructuresUsingTimeArgs(exec, args, 2, &ms, t);
     638    fillStructuresUsingTimeArgs(exec, args, 2, &ms, &t);
    753639    break;
    754640  case SetMinutes:
    755     fillStructuresUsingTimeArgs(exec, args, 3, &ms, t);
     641    fillStructuresUsingTimeArgs(exec, args, 3, &ms, &t);
    756642    break;
    757643  case SetHours:
    758     fillStructuresUsingTimeArgs(exec, args, 4, &ms, t);
     644    fillStructuresUsingTimeArgs(exec, args, 4, &ms, &t);
    759645    break;
    760646  case SetDate:
    761     fillStructuresUsingDateArgs(exec, args, 1, &ms, t);
     647    fillStructuresUsingDateArgs(exec, args, 1, &ms, &t);
    762648    break;
    763649  case SetMonth:
    764     fillStructuresUsingDateArgs(exec, args, 2, &ms, t);   
     650    fillStructuresUsingDateArgs(exec, args, 2, &ms, &t);   
    765651    break;
    766652  case SetFullYear:
    767     fillStructuresUsingDateArgs(exec, args, 3, &ms, t);
     653    fillStructuresUsingDateArgs(exec, args, 3, &ms, &t);
    768654    break;
    769655  case SetYear:
    770     t->tm_year = args[0]->toInt32(exec) >= 1900 ? args[0]->toInt32(exec) - 1900 : args[0]->toInt32(exec);
     656    t.tm_year = args[0]->toInt32(exec) >= 1900 ? args[0]->toInt32(exec) - 1900 : args[0]->toInt32(exec);
    771657    break;
    772658  }
     
    775661      id == SetMinutes || id == SetHours || id == SetDate ||
    776662      id == SetMonth || id == SetFullYear ) {
    777     result = Number(makeTime(t, ms, utc));
     663    result = jsNumber(makeTime(&t, ms, utc));
    778664    thisObj->setInternalValue(result);
    779665  }
     
    805691bool DateObjectImp::implementsConstruct() const
    806692{
    807   return true;
     693    return true;
    808694}
    809695
     
    813699  int numArgs = args.size();
    814700
    815 #ifdef KJS_VERBOSE
    816   fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs);
    817 #endif
    818701  double value;
    819702
    820703  if (numArgs == 0) { // new Date() ECMA 15.9.3.3
    821 #if HAVE_SYS_TIMEB_H
    822 #  if defined(__BORLANDC__)
     704#if !WIN32
     705    struct timeval tv;
     706    gettimeofday(&tv, 0);
     707    double utc = floor(tv.tv_sec * msPerSecond + tv.tv_usec / msPerSecond);
     708#else
     709#  if __BORLANDC__
    823710    struct timeb timebuffer;
    824711    ftime(&timebuffer);
     
    827714    _ftime(&timebuffer);
    828715#  endif
    829     double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm);
    830 #else
    831     struct timeval tv;
    832     // FIXME: not threadsafe
    833     gettimeofday(&tv, 0L);
    834     double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0);
     716    double utc = floor(timebuffer.time * msPerSecond + timebuffer.millitm);
    835717#endif
    836718    value = utc;
     
    850732      value = NaN;
    851733    } else {
    852       struct tm t;
     734      tm t;
    853735      memset(&t, 0, sizeof(t));
    854736      int year = args[0]->toInt32(exec);
     
    866748 
    867749  DateInstanceImp *ret = new DateInstanceImp(exec->lexicalInterpreter()->builtinDatePrototype());
    868   ret->setInternalValue(Number(timeClip(value)));
     750  ret->setInternalValue(jsNumber(timeClip(value)));
    869751  return ret;
    870752}
     
    872754bool DateObjectImp::implementsCall() const
    873755{
    874   return true;
     756    return true;
    875757}
    876758
     
    878760ValueImp *DateObjectImp::callAsFunction(ExecState * /*exec*/, ObjectImp * /*thisObj*/, const List &/*args*/)
    879761{
    880   time_t t = time(0L);
    881   // FIXME: not threadsafe
    882   struct tm *tm = localtime(&t);
    883   return String(formatDate(*tm) + " " + formatTime(*tm));
     762    time_t t = time(0);
     763    tm ts;
     764    localtime_r(&t, &ts);
     765    return jsString(formatDate(ts) + " " + formatTime(ts));
    884766}
    885767
    886768// ------------------------------ DateObjectFuncImp ----------------------------
    887769
    888 DateObjectFuncImp::DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto,
    889                                      int i, int len)
    890   : InternalFunctionImp(funcProto), id(i)
    891 {
    892   putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
     770DateObjectFuncImp::DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, int i, int len)
     771    : InternalFunctionImp(funcProto), id(i)
     772{
     773    putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
    893774}
    894775
    895776bool DateObjectFuncImp::implementsCall() const
    896777{
    897   return true;
     778    return true;
    898779}
    899780
     
    902783{
    903784  if (id == Parse) {
    904     return Number(parseDate(args[0]->toString(exec)));
     785    return jsNumber(parseDate(args[0]->toString(exec)));
    905786  }
    906787  else { // UTC
     
    913794        || (n >= 6 && isNaN(args[5]->toNumber(exec)))
    914795        || (n >= 7 && isNaN(args[6]->toNumber(exec)))) {
    915       return Number(NaN);
    916     }
    917 
    918     struct tm t;
     796      return jsNaN();
     797    }
     798
     799    tm t;
    919800    memset(&t, 0, sizeof(t));
    920801    int year = args[0]->toInt32(exec);
     
    926807    t.tm_sec = (n >= 6) ? args[5]->toInt32(exec) : 0;
    927808    double ms = (n >= 7) ? roundValue(exec, args[6]) : 0;
    928     return Number(makeTime(&t, ms, true));
     809    return jsNumber(makeTime(&t, ms, true));
    929810  }
    930811}
     
    932813// -----------------------------------------------------------------------------
    933814
    934 
    935 double parseDate(const UString &u)
    936 {
    937 #ifdef KJS_VERBOSE
    938   fprintf(stderr,"KJS::parseDate %s\n",u.ascii());
     815// Code originally from krfcdate.cpp, but we don't want to use kdecore, and we want double range.
     816
     817static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second)
     818{
     819    double days = (day - 32075)
     820        + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
     821        + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
     822        - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4)
     823        - 2440588;
     824    return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second;
     825}
     826
     827// We follow the recommendation of RFC 2822 to consider all
     828// obsolete time zones not listed here equivalent to "-0000".
     829static const struct KnownZone {
     830#if !WIN32
     831    const
    939832#endif
    940   double /*time_t*/ seconds = KRFCDate_parseDate( u );
    941 
    942   return seconds == invalidDate ? NaN : seconds * 1000.0;
    943 }
    944 
    945 ///// Awful duplication from krfcdate.cpp - we don't link to kdecore
    946 
    947 static double ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
    948 {
    949     double ret = (day - 32075)       /* days */
    950             + 1461L * (year + 4800L + (mon - 14) / 12) / 4
    951             + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
    952             - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
    953             - 2440588;
    954     ret = 24*ret + hour;     /* hours   */
    955     ret = 60*ret + minute;   /* minutes */
    956     ret = 60*ret + second;   /* seconds */
    957 
    958     return ret;
    959 }
    960 
    961 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
    962 
    963 // we follow the recommendation of rfc2822 to consider all
    964 // obsolete time zones not listed here equivalent to "-0000"
    965 static const struct KnownZone {
    966 #ifdef _WIN32
    967     char tzName[4];
    968 #else
    969     const char tzName[4];
    970 #endif
     833        char tzName[4];
    971834    int tzOffset;
    972835} known_zones[] = {
     
    983846};
    984847
    985 double makeTime(struct tm *t, double ms, bool utc)
     848static double makeTime(tm *t, double ms, bool utc)
    986849{
    987850    int utcOffset;
    988851    if (utc) {
    989852        time_t zero = 0;
    990 #if defined(WIN32)
    991         // FIXME: not threadsafe
     853#if !WIN32
     854        tm t3;
     855        localtime_r(&zero, &t3);
     856        utcOffset = t3.tm_gmtoff;
     857        t->tm_isdst = t3.tm_isdst;
     858#else
     859        // FIXME: not thread safe
    992860        (void)localtime(&zero);
    993 #  if defined(__BORLANDC__) || defined(__CYGWIN__)
     861#  if __BORLANDC__ || __CYGWIN__
    994862        utcOffset = - _timezone;
    995863#  else
     
    997865#  endif
    998866        t->tm_isdst = 0;
    999 #else
    1000         struct tm t3;
    1001         localtime_r(&zero, &t3);
    1002         utcOffset = t3.tm_gmtoff;
    1003         t->tm_isdst = t3.tm_isdst;
    1004867#endif
    1005868    } else {
     
    1008871    }
    1009872
    1010 #ifdef __APPLE__
    1011     // t->tm_year must hold the bulk of the data to avoid overflow when converting
    1012     // to a CFGregorianDate. (CFGregorianDate.month is an SInt8; CFGregorianDate.year is an SInt32.)
    1013     t->tm_year += t->tm_mon / 12;
    1014     t->tm_mon %= 12;
    1015 #endif   
    1016 
    1017873    double yearOffset = 0.0;
    1018874    if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) {
    1019       // we'll fool mktime() into believing that this year is within
    1020       // its normal, portable range (1970-2038) by setting tm_year to
    1021       // 2000 or 2001 and adding the difference in milliseconds later.
    1022       // choice between offset will depend on whether the year is a
    1023       // leap year or not.
    1024       int y = t->tm_year + 1900;
    1025       int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
    1026       const double baseTime = timeFromYear(baseYear);
    1027       yearOffset = timeFromYear(y) - baseTime;
    1028       t->tm_year = baseYear - 1900;
    1029     }
    1030 
    1031     return (mktime(t) + utcOffset) * 1000.0 + ms + yearOffset;
     875        // we'll fool mktime() into believing that this year is within
     876        // its normal, portable range (1970-2038) by setting tm_year to
     877        // 2000 or 2001 and adding the difference in milliseconds later.
     878        // choice between offset will depend on whether the year is a
     879        // leap year or not.
     880        int y = t->tm_year + 1900;
     881        int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
     882        double baseTime = timeFromYear(baseYear);
     883        yearOffset = timeFromYear(y) - baseTime;
     884        t->tm_year = baseYear - 1900;
     885    }
     886
     887    return (mktime(t) + utcOffset) * msPerSecond + ms + yearOffset;
    1032888}
    1033889
     
    1052908static int findMonth(const char *monthStr)
    1053909{
    1054   assert(monthStr);
    1055   static const char haystack[37] = "janfebmaraprmayjunjulaugsepoctnovdec";
    1056   char needle[4];
    1057   for (int i = 0; i < 3; ++i) {
    1058     if (!*monthStr)
    1059       return -1;
    1060     needle[i] = tolower(*monthStr++);
    1061   }
    1062   needle[3] = '\0';
    1063   const char *str = strstr(haystack, needle);
    1064   if (str) {
    1065     int position = str - haystack;
    1066     if (position % 3 == 0) {
    1067       return position / 3;
    1068     }
    1069   }
    1070   return -1;
    1071 }
    1072 
    1073 double KRFCDate_parseDate(const UString &_date)
    1074 {
    1075      // This parse a date in the form:
    1076      //     Tuesday, 09-Nov-99 23:12:40 GMT
    1077      // or
    1078      //     Sat, 01-Jan-2000 08:00:00 GMT
    1079      // or
    1080      //     Sat, 01 Jan 2000 08:00:00 GMT
    1081      // or
    1082      //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
    1083      // ### non RFC formats, added for Javascript:
    1084      //     [Wednesday] January 09 1999 23:12:40 GMT
    1085      //     [Wednesday] January 09 23:12:40 GMT 1999
    1086      //
    1087      // We ignore the weekday
    1088      //
    1089      double result = -1;
    1090      int offset = 0;
    1091      bool have_tz = false;
    1092      char *newPosStr;
    1093      const char *dateString = _date.ascii();
    1094      int day = 0;
    1095      int month = -1; // not set yet
    1096      int year = 0;
    1097      int hour = 0;
    1098      int minute = 0;
    1099      int second = 0;
    1100      bool have_time = false;
     910    assert(monthStr);
     911    char needle[4];
     912    for (int i = 0; i < 3; ++i) {
     913        if (!*monthStr)
     914            return -1;
     915        needle[i] = tolower(*monthStr++);
     916    }
     917    needle[3] = '\0';
     918    const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec";
     919    const char *str = strstr(haystack, needle);
     920    if (str) {
     921        int position = str - haystack;
     922        if (position % 3 == 0)
     923            return position / 3;
     924    }
     925    return -1;
     926}
     927
     928static double parseDate(const UString &date)
     929{
     930    // This parses a date in the form:
     931    //     Tuesday, 09-Nov-99 23:12:40 GMT
     932    // or
     933    //     Sat, 01-Jan-2000 08:00:00 GMT
     934    // or
     935    //     Sat, 01 Jan 2000 08:00:00 GMT
     936    // or
     937    //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
     938    // ### non RFC formats, added for Javascript:
     939    //     [Wednesday] January 09 1999 23:12:40 GMT
     940    //     [Wednesday] January 09 23:12:40 GMT 1999
     941    //
     942    // We ignore the weekday.
     943
     944    CString dateCString = date.UTF8String();
     945    const char *dateString = dateCString.c_str();
    1101946     
    1102      // Skip leading space
    1103      skipSpacesAndComments(dateString);
    1104 
    1105      const char *wordStart = dateString;
    1106      // Check contents of first words if not number
    1107      while (*dateString && !isdigit(*dateString)) {
     947    // Skip leading space
     948    skipSpacesAndComments(dateString);
     949
     950    long month = -1;
     951    const char *wordStart = dateString;
     952    // Check contents of first words if not number
     953    while (*dateString && !isdigit(*dateString)) {
    1108954        if (isspace(*dateString) || *dateString == '(') {
    1109            if (dateString - wordStart >= 3)
    1110               month = findMonth(wordStart);
    1111            skipSpacesAndComments(dateString);
    1112            wordStart = dateString;
    1113         }
    1114         else
     955            if (dateString - wordStart >= 3)
     956                month = findMonth(wordStart);
     957            skipSpacesAndComments(dateString);
     958            wordStart = dateString;
     959        } else
    1115960           dateString++;
    1116      }
    1117      // missing delimiter between month and day (like "January29")?
    1118      if (month == -1 && dateString && wordStart != dateString) {
    1119        month = findMonth(wordStart);
    1120        // TODO: emit warning about dubious format found
    1121      }
    1122 
    1123      skipSpacesAndComments(dateString);
    1124 
    1125      if (!*dateString)
    1126         return invalidDate;
    1127 
    1128      // ' 09-Nov-99 23:12:40 GMT'
    1129      errno = 0;
    1130     day = strtol(dateString, &newPosStr, 10);
    1131      if (errno)
    1132        return invalidDate;
    1133      dateString = newPosStr;
    1134 
    1135      if (!*dateString)
    1136         return invalidDate;
    1137 
    1138      if (day < 1)
    1139        return invalidDate;
    1140      if (day > 31) {
    1141        // ### where is the boundary and what happens below?
    1142        if (*dateString == '/' && day >= 1000) {
    1143          // looks like a YYYY/MM/DD date
    1144          if (!*++dateString)
    1145            return invalidDate;
    1146          year = day;
    1147          month = strtol(dateString, &newPosStr, 10) - 1;
    1148          if (errno)
    1149            return invalidDate;
    1150          dateString = newPosStr;
    1151          if (*dateString++ != '/' || !*dateString)
    1152            return invalidDate;
    1153          day = strtol(dateString, &newPosStr, 10);
    1154          if (errno)
    1155            return invalidDate;
    1156          dateString = newPosStr;
    1157        } else {
    1158          return invalidDate;
    1159        }
    1160      } else if (*dateString == '/' && day <= 12 && month == -1) {
     961    }
     962
     963    // Missing delimiter between month and day (like "January29")?
     964    if (month == -1 && dateString && wordStart != dateString)
     965        month = findMonth(wordStart);
     966
     967    skipSpacesAndComments(dateString);
     968
     969    if (!*dateString)
     970        return NaN;
     971
     972    // ' 09-Nov-99 23:12:40 GMT'
     973    char *newPosStr;
     974    errno = 0;
     975    long day = strtol(dateString, &newPosStr, 10);
     976    if (errno)
     977        return NaN;
     978    dateString = newPosStr;
     979
     980    if (!*dateString)
     981        return NaN;
     982
     983    if (day < 1)
     984        return NaN;
     985
     986    long year = 0;
     987    if (day > 31) {
     988        // ### where is the boundary and what happens below?
     989        if (!(*dateString == '/' && day >= 1000))
     990            return NaN;
     991        // looks like a YYYY/MM/DD date
     992        if (!*++dateString)
     993            return NaN;
     994        year = day;
     995        month = strtol(dateString, &newPosStr, 10) - 1;
     996        if (errno)
     997            return NaN;
     998        dateString = newPosStr;
     999        if (*dateString++ != '/' || !*dateString)
     1000            return NaN;
     1001        day = strtol(dateString, &newPosStr, 10);
     1002        if (errno)
     1003            return NaN;
     1004        dateString = newPosStr;
     1005    } else if (*dateString == '/' && day <= 12 && month == -1) {
    11611006        dateString++;
    1162         // This looks like a MM/DD/YYYY date, not an RFC date.....
     1007        // This looks like a MM/DD/YYYY date, not an RFC date.
    11631008        month = day - 1; // 0-based
    11641009        day = strtol(dateString, &newPosStr, 10);
    11651010        if (errno)
    1166           return invalidDate;
     1011            return NaN;
     1012        if (day < 1 || day > 31)
     1013            return NaN;
    11671014        dateString = newPosStr;
    11681015        if (*dateString == '/')
    1169           dateString++;
     1016            dateString++;
    11701017        if (!*dateString)
    1171           return invalidDate;
    1172      }
    1173      else
    1174      {
    1175        if (*dateString == '-')
    1176          dateString++;
    1177 
    1178        skipSpacesAndComments(dateString);
    1179 
    1180        if (*dateString == ',')
    1181          dateString++;
    1182 
    1183        if ( month == -1 ) // not found yet
    1184        {
    1185          month = findMonth(dateString);
    1186          if (month == -1)
    1187            return invalidDate;
    1188 
    1189          while (*dateString && (*dateString != '-') && !isspace(*dateString))
    1190            dateString++;
    1191 
    1192          if (!*dateString)
    1193            return invalidDate;
    1194 
    1195          // '-99 23:12:40 GMT'
    1196          if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString))
    1197            return invalidDate;
    1198          dateString++;
    1199        }
    1200 
    1201        if ((month < 0) || (month > 11))
    1202          return invalidDate;
    1203      }
    1204 
    1205      // '99 23:12:40 GMT'
    1206      if (year <= 0 && *dateString) {
    1207        year = strtol(dateString, &newPosStr, 10);
    1208        if (errno)
    1209          return invalidDate;
     1018            return NaN;
     1019     } else {
     1020        if (*dateString == '-')
     1021            dateString++;
     1022
     1023        skipSpacesAndComments(dateString);
     1024
     1025        if (*dateString == ',')
     1026            dateString++;
     1027
     1028        if (month == -1) { // not found yet
     1029            month = findMonth(dateString);
     1030            if (month == -1)
     1031                return NaN;
     1032
     1033            while (*dateString && (*dateString != '-') && !isspace(*dateString))
     1034                dateString++;
     1035
     1036            if (!*dateString)
     1037                return NaN;
     1038
     1039            // '-99 23:12:40 GMT'
     1040            if (*dateString != '-' && *dateString != '/' && !isspace(*dateString))
     1041                return NaN;
     1042            dateString++;
     1043        }
     1044    }
     1045
     1046    if (month < 0 || month > 11)
     1047        return NaN;
     1048
     1049    // '99 23:12:40 GMT'
     1050    if (year <= 0 && *dateString) {
     1051        year = strtol(dateString, &newPosStr, 10);
     1052        if (errno)
     1053            return NaN;
    12101054    }
    12111055   
    1212      // Don't fail if the time is missing.
    1213      if (*newPosStr)
    1214      {
     1056    // Don't fail if the time is missing.
     1057    long hour = 0;
     1058    long minute = 0;
     1059    long second = 0;
     1060    if (!*newPosStr)
     1061        dateString = newPosStr;
     1062    else {
    12151063        // ' 23:12:40 GMT'
    12161064        if (!isspace(*newPosStr)) {
    1217            if ( *newPosStr == ':' ) // Ah, so there was no year, but the number was the hour
    1218                year = -1;
    1219            else
    1220                return invalidDate;
     1065            if (*newPosStr != ':')
     1066                return NaN;
     1067            // There was no year; the number was the hour.
     1068            year = -1;
    12211069        } else {
    12221070            // in the normal case (we parsed the year), advance to the next number
     
    12261074
    12271075        hour = strtol(dateString, &newPosStr, 10);
    1228 
    12291076        // Do not check for errno here since we want to continue
    12301077        // even if errno was set becasue we are still looking
    12311078        // for the timezone!
    1232         // read a number? if not this might be a timezone name
     1079
     1080        // Read a number? If not, this might be a timezone name.
    12331081        if (newPosStr != dateString) {
    1234           have_time = true;
    1235           dateString = newPosStr;
    1236 
    1237           if ((hour < 0) || (hour > 23))
    1238             return invalidDate;
    1239 
    1240           if (!*dateString)
    1241             return invalidDate;
    1242 
    1243           // ':12:40 GMT'
    1244           if (*dateString++ != ':')
    1245             return invalidDate;
    1246 
    1247           minute = strtol(dateString, &newPosStr, 10);
    1248           if (errno)
    1249             return invalidDate;
    1250           dateString = newPosStr;
    1251 
    1252           if ((minute < 0) || (minute > 59))
    1253             return invalidDate;
    1254 
    1255           // ':40 GMT'
    1256           if (*dateString && *dateString != ':' && !isspace(*dateString))
    1257             return invalidDate;
    1258 
    1259           // seconds are optional in rfc822 + rfc2822
    1260           if (*dateString ==':') {
    1261             dateString++;
    1262 
    1263             second = strtol(dateString, &newPosStr, 10);
     1082            dateString = newPosStr;
     1083
     1084            if (hour < 0 || hour > 23)
     1085                return NaN;
     1086
     1087            if (!*dateString)
     1088                return NaN;
     1089
     1090            // ':12:40 GMT'
     1091            if (*dateString++ != ':')
     1092                return NaN;
     1093
     1094            minute = strtol(dateString, &newPosStr, 10);
    12641095            if (errno)
    1265               return invalidDate;
     1096                return NaN;
    12661097            dateString = newPosStr;
     1098
     1099            if (minute < 0 || minute > 59)
     1100                return NaN;
     1101
     1102            // ':40 GMT'
     1103            if (*dateString && *dateString != ':' && !isspace(*dateString))
     1104                return NaN;
     1105
     1106            // seconds are optional in rfc822 + rfc2822
     1107            if (*dateString ==':') {
     1108                dateString++;
     1109
     1110                second = strtol(dateString, &newPosStr, 10);
     1111                if (errno)
     1112                    return NaN;
     1113                dateString = newPosStr;
    12671114           
    1268             if ((second < 0) || (second > 59))
    1269               return invalidDate;
    1270           }
    1271 
    1272           skipSpacesAndComments(dateString);
    1273 
    1274           if (strncasecmp(dateString, "AM", 2) == 0) {
    1275             if (hour > 12)
    1276               return invalidDate;
    1277             if (hour == 12)
    1278               hour = 0;
    1279             dateString += 2;
     1115                if (second < 0 || second > 59)
     1116                    return NaN;
     1117            }
     1118
    12801119            skipSpacesAndComments(dateString);
    1281           } else if (strncasecmp(dateString, "PM", 2) == 0) {
    1282             if (hour > 12)
    1283               return invalidDate;
    1284             if (hour != 12)
    1285               hour += 12;
    1286             dateString += 2;
    1287             skipSpacesAndComments(dateString);
    1288           }
     1120
     1121            if (strncasecmp(dateString, "AM", 2) == 0) {
     1122                if (hour > 12)
     1123                    return NaN;
     1124                if (hour == 12)
     1125                    hour = 0;
     1126                dateString += 2;
     1127                skipSpacesAndComments(dateString);
     1128            } else if (strncasecmp(dateString, "PM", 2) == 0) {
     1129                if (hour > 12)
     1130                    return NaN;
     1131                if (hour != 12)
     1132                    hour += 12;
     1133                dateString += 2;
     1134                skipSpacesAndComments(dateString);
     1135            }
    12891136        }
    1290      } else {
    1291        dateString = newPosStr;
    1292      }
    1293 
    1294      // Don't fail if the time zone is missing.
    1295      // Some websites omit the time zone (4275206).
    1296      if (*dateString) {
    1297        if (strncasecmp(dateString, "GMT", 3) == 0 ||
    1298            strncasecmp(dateString, "UTC", 3) == 0) {
    1299          dateString += 3;
    1300          have_tz = true;
    1301        }
    1302 
    1303        skipSpacesAndComments(dateString);
    1304 
    1305        if (strncasecmp(dateString, "GMT", 3) == 0) {
    1306          dateString += 3;
    1307        }
    1308        if ((*dateString == '+') || (*dateString == '-')) {
    1309          offset = strtol(dateString, &newPosStr, 10);
    1310          if (errno)
    1311            return invalidDate;
    1312          dateString = newPosStr;
    1313 
    1314          if ((offset < -9959) || (offset > 9959))
    1315             return invalidDate;
    1316 
    1317          int sgn = (offset < 0)? -1:1;
    1318          offset = abs(offset);
    1319          if ( *dateString == ':' ) { // GMT+05:00
    1320            int offset2 = strtol(dateString, &newPosStr, 10);
    1321            if (errno)
    1322              return invalidDate;
    1323            dateString = newPosStr;
    1324            offset = (offset*60 + offset2)*sgn;
    1325          }
    1326          else
    1327            offset = ((offset / 100)*60 + (offset % 100))*sgn;
    1328          have_tz = true;
    1329        } else {
    1330          for (int i=0; i < int(sizeof(known_zones)/sizeof(KnownZone)); i++) {
    1331            if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
    1332              offset = known_zones[i].tzOffset;
    1333              dateString += strlen(known_zones[i].tzName);
    1334              have_tz = true;
    1335              break;
    1336            }
    1337          }
    1338        }
    1339      }
    1340 
    1341      skipSpacesAndComments(dateString);
    1342 
    1343      if ( *dateString && year == -1 ) {
    1344        year = strtol(dateString, &newPosStr, 10);
    1345        if (errno)
    1346          return invalidDate;
    1347        dateString = newPosStr;
    1348      }
     1137    }
     1138
     1139    bool haveTZ = false;
     1140    int offset = 0;
     1141
     1142    // Don't fail if the time zone is missing.
     1143    // Some websites omit the time zone (4275206).
     1144    if (*dateString) {
     1145        if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) {
     1146            dateString += 3;
     1147            haveTZ = true;
     1148        }
     1149
     1150        if (*dateString == '+' || *dateString == '-') {
     1151            long o = strtol(dateString, &newPosStr, 10);
     1152            if (errno)
     1153                return NaN;
     1154            dateString = newPosStr;
     1155
     1156            if (o < -9959 || o > 9959)
     1157                return NaN;
     1158
     1159            int sgn = (o < 0) ? -1 : 1;
     1160            o = abs(o);
     1161            if (*dateString != ':') {
     1162                offset = ((o / 100) * 60 + (o % 100)) * sgn;
     1163            } else { // GMT+05:00
     1164                long o2 = strtol(dateString, &newPosStr, 10);
     1165                if (errno)
     1166                    return NaN;
     1167                dateString = newPosStr;
     1168                offset = (o * 60 + o2) * sgn;
     1169            }
     1170            haveTZ = true;
     1171        } else {
     1172            for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) {
     1173                if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
     1174                    offset = known_zones[i].tzOffset;
     1175                    dateString += strlen(known_zones[i].tzName);
     1176                    haveTZ = true;
     1177                    break;
     1178                }
     1179            }
     1180        }
     1181    }
     1182
     1183    skipSpacesAndComments(dateString);
     1184
     1185    if (*dateString && year == -1) {
     1186        year = strtol(dateString, &newPosStr, 10);
     1187        if (errno)
     1188            return NaN;
     1189        dateString = newPosStr;
     1190    }
    13491191     
    1350      skipSpacesAndComments(dateString);
     1192    skipSpacesAndComments(dateString);
    13511193     
    1352      // Trailing garbage
    1353      if (*dateString != '\0')
    1354        return invalidDate;
    1355 
    1356      // Y2K: Solve 2 digit years
    1357      if ((year >= 0) && (year < 50))
    1358          year += 2000;
    1359 
    1360      if ((year >= 50) && (year < 100))
    1361          year += 1900;  // Y2K
    1362 
    1363      // fall back to midnight, local timezone
    1364      if (!have_tz) {
    1365        struct tm t;
    1366        memset(&t, 0, sizeof(tm));
    1367        t.tm_mday = day;
    1368        t.tm_mon = month;
    1369        t.tm_year = year - 1900;
    1370        t.tm_isdst = -1;
    1371        if (have_time) {
    1372          t.tm_sec = second;
    1373          t.tm_min = minute;
    1374          t.tm_hour = hour;
    1375        }
    1376 
    1377        // better not use mktime() as it can't handle the full year range
    1378        return makeTime(&t, 0, false) / 1000.0;
    1379      }
    1380      
    1381      result = ymdhms_to_seconds(year, month + 1, day, hour, minute, second) - (offset * 60);
    1382      return result;
    1383 }
    1384 
     1194    // Trailing garbage
     1195    if (*dateString)
     1196        return NaN;
     1197
     1198    // Y2K: Handle 2 digit years.
     1199    if (year >= 0 && year < 100) {
     1200        if (year < 50)
     1201            year += 2000;
     1202        else
     1203            year += 1900;
     1204    }
     1205
     1206    // fall back to local timezone
     1207    if (!haveTZ) {
     1208        tm t;
     1209        memset(&t, 0, sizeof(tm));
     1210        t.tm_mday = day;
     1211        t.tm_mon = month;
     1212        t.tm_year = year - 1900;
     1213        t.tm_isdst = -1;
     1214        t.tm_sec = second;
     1215        t.tm_min = minute;
     1216        t.tm_hour = hour;
     1217
     1218        // Use our makeTime() rather than mktime() as the latter can't handle the full year range.
     1219        return makeTime(&t, 0, false);
     1220    }
     1221
     1222    return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond;
     1223}
    13851224
    13861225double timeClip(double t)
  • trunk/JavaScriptCore/kjs/date_object.h

    r10456 r10801  
    1 // -*- c-basic-offset: 2 -*-
    21/*
    32 *  This file is part of the KDE libraries
     
    2019 */
    2120
    22 #ifndef _DATE_OBJECT_H_
    23 #define _DATE_OBJECT_H_
     21#ifndef DATE_OBJECT_H
     22#define DATE_OBJECT_H
    2423
    2524#include "internal.h"
    26 #include "function_object.h"
    2725
    2826namespace KJS {
    2927
    30   class DateInstanceImp : public ObjectImp {
    31   public:
    32     DateInstanceImp(ObjectImp *proto);
     28    class FunctionPrototypeImp;
     29    class ObjectPrototypeImp;
    3330
    34     virtual const ClassInfo *classInfo() const { return &info; }
    35     static const ClassInfo info;
    36   };
     31    class DateInstanceImp : public ObjectImp {
     32    public:
     33        DateInstanceImp(ObjectImp *proto);
    3734
    38   /**
    39    * @internal
    40    *
    41    * The initial value of Date.prototype (and thus all objects created
    42    * with the Date constructor
    43    */
    44   class DatePrototypeImp : public DateInstanceImp {
    45   public:
    46     DatePrototypeImp(ExecState *exec, ObjectPrototypeImp *objectProto);
    47     bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot&);
    48     virtual const ClassInfo *classInfo() const { return &info; }
    49     static const ClassInfo info;
    50   };
     35        virtual const ClassInfo *classInfo() const { return &info; }
     36        static const ClassInfo info;
     37    };
    5138
    52   /**
    53    * @internal
    54    *
    55    * Class to implement all methods that are properties of the
    56    * Date.prototype object
    57    */
    58   class DateProtoFuncImp : public InternalFunctionImp {
    59   public:
    60     DateProtoFuncImp(ExecState *exec, int i, int len);
     39    /**
     40     * @internal
     41     *
     42     * The initial value of Date.prototype (and thus all objects created
     43     * with the Date constructor
     44     */
     45    class DatePrototypeImp : public DateInstanceImp {
     46    public:
     47        DatePrototypeImp(ExecState *, ObjectPrototypeImp *);
     48        virtual bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot&);
     49        virtual const ClassInfo *classInfo() const { return &info; }
     50        static const ClassInfo info;
     51    };
    6152
    62     virtual bool implementsCall() const;
    63     virtual ValueImp *callAsFunction(ExecState *exec, ObjectImp *thisObj, const List &args);
     53    /**
     54     * @internal
     55     *
     56     * The initial value of the the global variable's "Date" property
     57     */
     58    class DateObjectImp : public InternalFunctionImp {
     59    public:
     60        DateObjectImp(ExecState *, FunctionPrototypeImp *, DatePrototypeImp *);
    6461
     62        virtual bool implementsConstruct() const;
     63        virtual ObjectImp *construct(ExecState *, const List &args);
     64        virtual bool implementsCall() const;
     65        virtual ValueImp *callAsFunction(ExecState *, ObjectImp *thisObj, const List &args);
    6566
    66     Completion execute(const List &);
    67     enum { ToString, ToDateString, ToTimeString, ToLocaleString,
    68            ToLocaleDateString, ToLocaleTimeString, ValueOf, GetTime,
    69            GetFullYear, GetMonth, GetDate, GetDay, GetHours, GetMinutes,
    70            GetSeconds, GetMilliSeconds, GetTimezoneOffset, SetTime,
    71            SetMilliSeconds, SetSeconds, SetMinutes, SetHours, SetDate,
    72            SetMonth, SetFullYear, ToUTCString,
    73            // non-normative properties (Appendix B)
    74            GetYear, SetYear, ToGMTString };
    75   private:
    76     int id;
    77     bool utc;
    78   };
    79 
    80   /**
    81    * @internal
    82    *
    83    * The initial value of the the global variable's "Date" property
    84    */
    85   class DateObjectImp : public InternalFunctionImp {
    86   public:
    87     DateObjectImp(ExecState *exec,
    88                   FunctionPrototypeImp *funcProto,
    89                   DatePrototypeImp *dateProto);
    90 
    91     virtual bool implementsConstruct() const;
    92     virtual ObjectImp *construct(ExecState *exec, const List &args);
    93     virtual bool implementsCall() const;
    94     virtual ValueImp *callAsFunction(ExecState *exec, ObjectImp *thisObj, const List &args);
    95 
    96     Completion execute(const List &);
    97     ObjectImp *construct(const List &);
    98   };
    99 
    100   /**
    101    * @internal
    102    *
    103    * Class to implement all methods that are properties of the
    104    * Date object
    105    */
    106   class DateObjectFuncImp : public InternalFunctionImp {
    107   public:
    108     DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto,
    109                       int i, int len);
    110 
    111     virtual bool implementsCall() const;
    112     virtual ValueImp *callAsFunction(ExecState *exec, ObjectImp *thisObj, const List &args);
    113 
    114     enum { Parse, UTC };
    115   private:
    116     int id;
    117   };
    118 
    119   // helper functions
    120   double parseDate(const UString &u);
    121   double KRFCDate_parseDate(const UString &_date);
    122   double timeClip(double t);
    123   double makeTime(struct tm *t, double milli, bool utc);
     67        Completion execute(const List &);
     68        ObjectImp *construct(const List &);
     69    };
    12470
    12571} // namespace
Note: See TracChangeset for help on using the changeset viewer.