Changeset 10801 in webkit for trunk/JavaScriptCore
- Timestamp:
- Oct 9, 2005, 3:56:30 PM (20 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r10800 r10801 1 2005-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 1 38 2005-10-08 Mitz Pettel <[email protected]> 2 39 -
trunk/JavaScriptCore/kjs/config.h
r10798 r10801 9 9 #define HAVE_SYS_PARAM_H 1 10 10 #define HAVE_SYS_TIME_H 1 11 #define TIME_WITH_SYS_TIME111 #define HAVE_SYS_TIMEB_H 1 12 12 13 13 #elif WIN32 … … 27 27 #define HAVE_SYS_PARAM_H 1 28 28 #define HAVE_SYS_TIME_H 1 29 #define TIME_WITH_SYS_TIME 130 29 31 30 #endif -
trunk/JavaScriptCore/kjs/date_object.cpp
r10800 r10801 1 // -*- c-basic-offset: 2 -*-2 1 /* 3 2 * This file is part of the KDE libraries … … 22 21 23 22 #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> 26 27 #endif 27 28 28 #if TIME_WITH_SYS_TIME29 # include <sys/time.h>30 # include <time.h>31 #else 29 #if HAVE_SYS_PARAM_H 30 #include <sys/param.h> 31 #endif 32 32 33 #if HAVE_SYS_TIME_H 33 34 #include <sys/time.h> 34 #else35 # include <time.h>36 # endif37 35 #endif 36 38 37 #if HAVE_SYS_TIMEB_H 39 38 #include <sys/timeb.h> 40 39 #endif 41 40 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> 50 45 #include <math.h> 51 #include <string.h>52 46 #include <stdio.h> 53 47 #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 59 51 #include "error_object.h" 60 52 #include "operations.h" 61 53 54 #if __APPLE__ 55 #include <CoreFoundation/CoreFoundation.h> 56 #endif 57 62 58 #if WIN32 59 #define copysign(x, y) _copysign(x, y) 60 #define isfinite(x) _finite(x) 63 61 #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)67 62 #endif 68 63 64 namespace KJS { 65 66 /** 67 * @internal 68 * 69 * Class to implement all methods that are properties of the 70 * Date.prototype object 71 */ 72 class DateProtoFuncImp : public InternalFunctionImp { 73 public: 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 }; 88 private: 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 */ 99 class DateObjectFuncImp : public InternalFunctionImp { 100 public: 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 108 private: 109 int id; 110 }; 111 112 } 113 69 114 #include "date_object.lut.h" 70 115 116 namespace KJS { 117 71 118 // some constants 72 const time_t invalidDate = LONG_MIN;73 119 const double hoursPerDay = 24; 74 120 const double minutesPerHour = 60; … … 81 127 static const char * const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 82 128 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", ¬ificationToken); 144 if (status == NOTIFY_STATUS_OK) { 145 registered = true; 146 } 147 } 148 if (registered) { 149 int notified; 150 uint32_t status = notify_check(notificationToken, ¬ified); 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; 129 static double makeTime(tm *, double ms, bool utc); 130 static double parseDate(const UString &); 131 static double timeClip(double); 132 133 #if __APPLE__ 134 135 static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle) 136 { 231 137 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 148 static 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()) { 256 158 useCustomFormat = true; 257 159 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 268 173 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); 271 176 CFRelease(customFormatCFString); 272 177 } 273 CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(NULL, formatter, time - kCFAbsoluteTimeIntervalSince1970); 178 179 CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, time - kCFAbsoluteTimeIntervalSince1970); 180 181 CFRelease(formatter); 182 274 183 // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters). 275 184 // That's not great error handling, but it just won't happen so it doesn't matter. … … 283 192 284 193 CFRelease(string); 285 CFRelease(formatter); 286 CFRelease(locale); 287 194 288 195 return UString(buffer, length); 289 196 } 290 197 291 #endif // APPLE_CHANGES 292 293 namespace KJS { 294 295 static UString formatDate(struct tm &tm) 198 #endif // __APPLE__ 199 200 static UString formatDate(const tm &t) 296 201 { 297 202 char buffer[100]; 298 203 snprintf(buffer, sizeof(buffer), "%s %s %02d %04d", 299 weekdayName[(t m.tm_wday + 6) % 7],300 monthName[t m.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); 301 206 return buffer; 302 207 } 303 208 304 static UString formatDateUTCVariant( struct tm &tm)209 static UString formatDateUTCVariant(const tm &t) 305 210 { 306 211 char buffer[100]; 307 212 snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d", 308 weekdayName[(t m.tm_wday + 6) % 7],309 t m.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); 310 215 return buffer; 311 216 } 312 217 313 static UString formatTime( struct tm &tm)218 static UString formatTime(const tm &t) 314 219 { 315 220 char buffer[100]; 316 if (t m.tm_gmtoff == 0) {317 snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t m.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); 318 223 } else { 319 int offset = tm.tm_gmtoff; 320 if (offset < 0) { 321 offset = -offset; 322 } 224 int offset = abs(t.tm_gmtoff); 323 225 snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d", 324 t m.tm_hour, tm.tm_min, tm.tm_sec,325 t m.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); 326 228 } 327 229 return UString(buffer); … … 330 232 static int day(double t) 331 233 { 332 return int(floor(t / msPerDay));234 return int(floor(t / msPerDay)); 333 235 } 334 236 335 237 static double dayFromYear(int year) 336 238 { 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 onwhether it's a leap year or not239 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 344 246 static int daysInYear(int year) 345 247 { 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; 353 254 return 366; 354 255 } … … 357 258 static double timeFromYear(int year) 358 259 { 359 return msPerDay * dayFromYear(year);260 return msPerDay * dayFromYear(year); 360 261 } 361 262 … … 363 264 static int yearFromTime(double t) 364 265 { 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; 379 282 } 380 283 … … 382 285 static int weekDay(double t) 383 286 { 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 293 static long timeZoneOffset(const tm &t) 294 { 295 #if !WIN32 296 return -(t.tm_gmtoff / 60); 394 297 #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); 401 305 # else 402 return timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 );306 return timezone / 60 - (t.tm_isdst > 0 ? 60 : 0 ); 403 307 # endif 404 308 #endif … … 409 313 // 410 314 // Format of member function: f([hour,] [min,] [sec,] [ms]) 411 static void fillStructuresUsingTimeArgs(ExecState *exec, const List &args, int maxArgs, double *ms, structtm *t)315 static void fillStructuresUsingTimeArgs(ExecState *exec, const List &args, int maxArgs, double *ms, tm *t) 412 316 { 413 317 double milliseconds = 0; … … 451 355 // 452 356 // Format of member function: f([years,] [months,] [days]) 453 static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, structtm *t)454 { 455 int idx = 0;456 int numArgs = args.size();357 static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, tm *t) 358 { 359 int idx = 0; 360 int numArgs = args.size(); 457 361 458 // JS allows extra trailing arguments -- ignore them459 if (numArgs > maxArgs)460 numArgs = maxArgs;362 // JS allows extra trailing arguments -- ignore them 363 if (numArgs > maxArgs) 364 numArgs = maxArgs; 461 365 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; 466 369 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); 471 373 472 // days473 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 } 477 379 } 478 380 … … 541 443 // ECMA 15.9.4 542 444 543 DatePrototypeImp::DatePrototypeImp(ExecState *, 544 ObjectPrototypeImp *objectProto) 445 DatePrototypeImp::DatePrototypeImp(ExecState *, ObjectPrototypeImp *objectProto) 545 446 : DateInstanceImp(objectProto) 546 447 { 547 setInternalValue(jsNaN());548 // The constructor will be added later, after DateObjectImp has been built448 setInternalValue(jsNaN()); 449 // The constructor will be added later, after DateObjectImp has been built. 549 450 } 550 451 551 452 bool DatePrototypeImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) 552 453 { 553 return getStaticFunctionSlot<DateProtoFuncImp, ObjectImp>(exec, &dateTable, this, propertyName, slot);454 return getStaticFunctionSlot<DateProtoFuncImp, ObjectImp>(exec, &dateTable, this, propertyName, slot); 554 455 } 555 456 … … 557 458 558 459 DateProtoFuncImp::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) 562 462 // We use a negative ID to denote the "UTC" variant. 563 463 { 564 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);464 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum); 565 465 } 566 466 567 467 bool DateProtoFuncImp::implementsCall() const 568 468 { 569 return true;469 return true; 570 470 } 571 471 … … 582 482 583 483 584 ValueImp *result = NULL;484 ValueImp *result = 0; 585 485 UString s; 586 #if ! defined(APPLE_CHANGES) || !APPLE_CHANGES486 #if !__APPLE__ 587 487 const int bufsize=100; 588 488 char timebuffer[bufsize]; 589 CString oldlocale = setlocale(LC_TIME, NULL);489 CString oldlocale = setlocale(LC_TIME, 0); 590 490 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? 592 493 #endif 593 494 ValueImp *v = thisObj->internalValue(); … … 603 504 case ToLocaleDateString: 604 505 case ToLocaleTimeString: 605 return String("Invalid Date");506 return jsString("Invalid Date"); 606 507 case ValueOf: 607 508 case GetTime: … … 624 525 int realYearOffset = 0; 625 526 double milliOffset = 0.0; 626 double secs = floor(milli / 1000.0);527 double secs = floor(milli / msPerSecond); 627 528 628 529 if (milli < 0 || milli >= timeFromYear(2038)) { … … 635 536 } 636 537 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 offset643 // 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. 644 545 if (realYearOffset != 0) { 645 t ->tm_year += realYearOffset;546 t.tm_year += realYearOffset; 646 547 milli -= milliOffset; 647 // our own weekday calculation. beware of need forlocal time.548 // Do our own weekday calculation. Use time zone offset to handle local time. 648 549 double m = milli; 649 550 if (!utc) 650 551 m -= timeZoneOffset(t) * msPerMinute; 651 t ->tm_wday = weekDay(m);552 t.tm_wday = weekDay(m); 652 553 } 653 554 654 555 switch (id) { 655 556 case ToString: 656 result = String(formatDate(*t) + " " + formatTime(*t)); 657 break; 557 return jsString(formatDate(t) + " " + formatTime(t)); 658 558 case ToDateString: 659 re sult = String(formatDate(*t));559 return jsString(formatDate(t)); 660 560 break; 661 561 case ToTimeString: 662 re sult = String(formatTime(*t));562 return jsString(formatTime(t)); 663 563 break; 664 564 case ToGMTString: 665 565 case ToUTCString: 666 re sult = String(formatDateUTCVariant(*t) + " " + formatTime(*t));667 break; 668 #if APPLE_CHANGES566 return jsString(formatDateUTCVariant(t) + " " + formatTime(t)); 567 break; 568 #if __APPLE__ 669 569 case ToLocaleString: 670 re sult =String(formatLocaleDate(exec, secs, true, true, args));570 return jsString(formatLocaleDate(exec, secs, true, true, args)); 671 571 break; 672 572 case ToLocaleDateString: 673 re sult =String(formatLocaleDate(exec, secs, true, false, args));573 return jsString(formatLocaleDate(exec, secs, true, false, args)); 674 574 break; 675 575 case ToLocaleTimeString: 676 re sult =String(formatLocaleDate(exec, secs, false, true, args));576 return jsString(formatLocaleDate(exec, secs, false, true, args)); 677 577 break; 678 578 #else 679 579 case ToLocaleString: 680 580 strftime(timebuffer, bufsize, "%c", t); 681 re sult =String(timebuffer);581 return jsString(timebuffer); 682 582 break; 683 583 case ToLocaleDateString: 684 584 strftime(timebuffer, bufsize, "%x", t); 685 re sult =String(timebuffer);585 return jsString(timebuffer); 686 586 break; 687 587 case ToLocaleTimeString: 688 588 strftime(timebuffer, bufsize, "%X", t); 689 re sult =String(timebuffer);589 return jsString(timebuffer); 690 590 break; 691 591 #endif 692 592 case ValueOf: 693 result = Number(milli);694 break;695 593 case GetTime: 696 result = Number(milli); 697 break; 594 return jsNumber(milli); 698 595 case GetYear: 699 596 // 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); 705 600 case GetFullYear: 706 result = Number(1900 + t->tm_year); 707 break; 601 return jsNumber(1900 + t.tm_year); 708 602 case GetMonth: 709 result = Number(t->tm_mon); 710 break; 603 return jsNumber(t.tm_mon); 711 604 case GetDate: 712 result = Number(t->tm_mday); 713 break; 605 return jsNumber(t.tm_mday); 714 606 case GetDay: 715 result = Number(t->tm_wday); 716 break; 607 return jsNumber(t.tm_wday); 717 608 case GetHours: 718 result = Number(t->tm_hour); 719 break; 609 return jsNumber(t.tm_hour); 720 610 case GetMinutes: 721 result = Number(t->tm_min); 722 break; 611 return jsNumber(t.tm_min); 723 612 case GetSeconds: 724 result = Number(t->tm_sec); 725 break; 613 return jsNumber(t.tm_sec); 726 614 case GetMilliSeconds: 727 result = Number(ms); 728 break; 615 return jsNumber(ms); 729 616 case GetTimezoneOffset: 730 #if WIN32 731 # if defined(__BORLANDC__) 617 #if !WIN32 618 return jsNumber(-t.tm_gmtoff / 60); 619 #else 620 # if __BORLANDC__ 732 621 #error please add daylight savings offset here! 733 622 // FIXME: Using the daylight value was wrong for BSD, maybe wrong here too. 734 re sult =Number(_timezone / 60 - (_daylight ? 60 : 0));623 return jsNumber(_timezone / 60 - (_daylight ? 60 : 0)); 735 624 # else 736 625 // FIXME: Using the daylight value was wrong for BSD, maybe wrong here too. 737 re sult = Number(( timezone / 60 - (daylight ? 60 : 0 )));626 return jsNumber(( timezone / 60 - (daylight ? 60 : 0 ))); 738 627 # endif 739 #else740 result = Number(-t->tm_gmtoff / 60);741 628 #endif 742 break;743 629 case SetTime: 744 630 milli = roundValue(exec, args[0]); 745 result = Number(milli);631 result = jsNumber(milli); 746 632 thisObj->setInternalValue(result); 747 633 break; 748 634 case SetMilliSeconds: 749 fillStructuresUsingTimeArgs(exec, args, 1, &ms, t);635 fillStructuresUsingTimeArgs(exec, args, 1, &ms, &t); 750 636 break; 751 637 case SetSeconds: 752 fillStructuresUsingTimeArgs(exec, args, 2, &ms, t);638 fillStructuresUsingTimeArgs(exec, args, 2, &ms, &t); 753 639 break; 754 640 case SetMinutes: 755 fillStructuresUsingTimeArgs(exec, args, 3, &ms, t);641 fillStructuresUsingTimeArgs(exec, args, 3, &ms, &t); 756 642 break; 757 643 case SetHours: 758 fillStructuresUsingTimeArgs(exec, args, 4, &ms, t);644 fillStructuresUsingTimeArgs(exec, args, 4, &ms, &t); 759 645 break; 760 646 case SetDate: 761 fillStructuresUsingDateArgs(exec, args, 1, &ms, t);647 fillStructuresUsingDateArgs(exec, args, 1, &ms, &t); 762 648 break; 763 649 case SetMonth: 764 fillStructuresUsingDateArgs(exec, args, 2, &ms, t);650 fillStructuresUsingDateArgs(exec, args, 2, &ms, &t); 765 651 break; 766 652 case SetFullYear: 767 fillStructuresUsingDateArgs(exec, args, 3, &ms, t);653 fillStructuresUsingDateArgs(exec, args, 3, &ms, &t); 768 654 break; 769 655 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); 771 657 break; 772 658 } … … 775 661 id == SetMinutes || id == SetHours || id == SetDate || 776 662 id == SetMonth || id == SetFullYear ) { 777 result = Number(makeTime(t, ms, utc));663 result = jsNumber(makeTime(&t, ms, utc)); 778 664 thisObj->setInternalValue(result); 779 665 } … … 805 691 bool DateObjectImp::implementsConstruct() const 806 692 { 807 return true;693 return true; 808 694 } 809 695 … … 813 699 int numArgs = args.size(); 814 700 815 #ifdef KJS_VERBOSE816 fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs);817 #endif818 701 double value; 819 702 820 703 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__ 823 710 struct timeb timebuffer; 824 711 ftime(&timebuffer); … … 827 714 _ftime(&timebuffer); 828 715 # 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); 835 717 #endif 836 718 value = utc; … … 850 732 value = NaN; 851 733 } else { 852 structtm t;734 tm t; 853 735 memset(&t, 0, sizeof(t)); 854 736 int year = args[0]->toInt32(exec); … … 866 748 867 749 DateInstanceImp *ret = new DateInstanceImp(exec->lexicalInterpreter()->builtinDatePrototype()); 868 ret->setInternalValue( Number(timeClip(value)));750 ret->setInternalValue(jsNumber(timeClip(value))); 869 751 return ret; 870 752 } … … 872 754 bool DateObjectImp::implementsCall() const 873 755 { 874 return true;756 return true; 875 757 } 876 758 … … 878 760 ValueImp *DateObjectImp::callAsFunction(ExecState * /*exec*/, ObjectImp * /*thisObj*/, const List &/*args*/) 879 761 { 880 time_t t = time(0L);881 // FIXME: not threadsafe882 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)); 884 766 } 885 767 886 768 // ------------------------------ DateObjectFuncImp ---------------------------- 887 769 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); 770 DateObjectFuncImp::DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, int i, int len) 771 : InternalFunctionImp(funcProto), id(i) 772 { 773 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum); 893 774 } 894 775 895 776 bool DateObjectFuncImp::implementsCall() const 896 777 { 897 return true;778 return true; 898 779 } 899 780 … … 902 783 { 903 784 if (id == Parse) { 904 return Number(parseDate(args[0]->toString(exec)));785 return jsNumber(parseDate(args[0]->toString(exec))); 905 786 } 906 787 else { // UTC … … 913 794 || (n >= 6 && isNaN(args[5]->toNumber(exec))) 914 795 || (n >= 7 && isNaN(args[6]->toNumber(exec)))) { 915 return Number(NaN);916 } 917 918 structtm t;796 return jsNaN(); 797 } 798 799 tm t; 919 800 memset(&t, 0, sizeof(t)); 920 801 int year = args[0]->toInt32(exec); … … 926 807 t.tm_sec = (n >= 6) ? args[5]->toInt32(exec) : 0; 927 808 double ms = (n >= 7) ? roundValue(exec, args[6]) : 0; 928 return Number(makeTime(&t, ms, true));809 return jsNumber(makeTime(&t, ms, true)); 929 810 } 930 811 } … … 932 813 // ----------------------------------------------------------------------------- 933 814 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 817 static 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". 829 static const struct KnownZone { 830 #if !WIN32 831 const 939 832 #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]; 971 834 int tzOffset; 972 835 } known_zones[] = { … … 983 846 }; 984 847 985 double makeTime(structtm *t, double ms, bool utc)848 static double makeTime(tm *t, double ms, bool utc) 986 849 { 987 850 int utcOffset; 988 851 if (utc) { 989 852 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 992 860 (void)localtime(&zero); 993 # if defined(__BORLANDC__) || defined(__CYGWIN__)861 # if __BORLANDC__ || __CYGWIN__ 994 862 utcOffset = - _timezone; 995 863 # else … … 997 865 # endif 998 866 t->tm_isdst = 0; 999 #else1000 struct tm t3;1001 localtime_r(&zero, &t3);1002 utcOffset = t3.tm_gmtoff;1003 t->tm_isdst = t3.tm_isdst;1004 867 #endif 1005 868 } else { … … 1008 871 } 1009 872 1010 #ifdef __APPLE__1011 // t->tm_year must hold the bulk of the data to avoid overflow when converting1012 // 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 #endif1016 1017 873 double yearOffset = 0.0; 1018 874 if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) { 1019 // we'll fool mktime() into believing that this year is within1020 // its normal, portable range (1970-2038) by setting tm_year to1021 // 2000 or 2001 and adding the difference in milliseconds later.1022 // choice between offset will depend on whether the year is a1023 // leap year or not.1024 int y = t->tm_year + 1900;1025 int baseYear = daysInYear(y) == 365 ? 2001 : 2000;1026 constdouble 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; 1032 888 } 1033 889 … … 1052 908 static int findMonth(const char *monthStr) 1053 909 { 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 928 static 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(); 1101 946 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)) { 1108 954 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 1115 960 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 found1121 } 1122 1123 skipSpacesAndComments(dateString); 1124 1125 if (!*dateString)1126 return invalidDate; 1127 1128 // ' 09-Nov-99 23:12:40 GMT'1129 1130 day = strtol(dateString, &newPosStr, 10);1131 1132 return invalidDate;1133 1134 1135 1136 return invalidDate;1137 1138 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 date1144 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 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) { 1161 1006 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. 1163 1008 month = day - 1; // 0-based 1164 1009 day = strtol(dateString, &newPosStr, 10); 1165 1010 if (errno) 1166 return invalidDate; 1011 return NaN; 1012 if (day < 1 || day > 31) 1013 return NaN; 1167 1014 dateString = newPosStr; 1168 1015 if (*dateString == '/') 1169 dateString++;1016 dateString++; 1170 1017 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; 1210 1054 } 1211 1055 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 { 1215 1063 // ' 23:12:40 GMT' 1216 1064 if (!isspace(*newPosStr)) { 1217 if ( *newPosStr == ':' ) // Ah, so there was no year, but the number was the hour1218 year = -1;1219 else1220 return invalidDate;1065 if (*newPosStr != ':') 1066 return NaN; 1067 // There was no year; the number was the hour. 1068 year = -1; 1221 1069 } else { 1222 1070 // in the normal case (we parsed the year), advance to the next number … … 1226 1074 1227 1075 hour = strtol(dateString, &newPosStr, 10); 1228 1229 1076 // Do not check for errno here since we want to continue 1230 1077 // even if errno was set becasue we are still looking 1231 1078 // 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. 1233 1081 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); 1264 1095 if (errno) 1265 return invalidDate;1096 return NaN; 1266 1097 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; 1267 1114 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 1280 1119 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 } 1289 1136 } 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 } 1349 1191 1350 1192 skipSpacesAndComments(dateString); 1351 1193 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 } 1385 1224 1386 1225 double timeClip(double t) -
trunk/JavaScriptCore/kjs/date_object.h
r10456 r10801 1 // -*- c-basic-offset: 2 -*-2 1 /* 3 2 * This file is part of the KDE libraries … … 20 19 */ 21 20 22 #ifndef _DATE_OBJECT_H_23 #define _DATE_OBJECT_H_21 #ifndef DATE_OBJECT_H 22 #define DATE_OBJECT_H 24 23 25 24 #include "internal.h" 26 #include "function_object.h"27 25 28 26 namespace KJS { 29 27 30 class DateInstanceImp : public ObjectImp { 31 public: 32 DateInstanceImp(ObjectImp *proto); 28 class FunctionPrototypeImp; 29 class ObjectPrototypeImp; 33 30 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); 37 34 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 }; 51 38 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 }; 61 52 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 *); 64 61 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); 65 66 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 }; 124 70 125 71 } // namespace
Note:
See TracChangeset
for help on using the changeset viewer.