2025-02-05 12:40:54 +10:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
2023-07-12 13:27:26 +10:00
|
|
|
* vim: set ts=8 sw=4 et tw=78:
|
2018-09-08 18:08:48 +08:00
|
|
|
*
|
|
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
|
*
|
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
|
*
|
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
|
* License.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Mozilla Communicator client code, released
|
|
|
|
|
* March 31, 1998.
|
|
|
|
|
*
|
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s):
|
|
|
|
|
*
|
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
|
*
|
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* JS date methods.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* "For example, OS/360 devotes 26 bytes of the permanently
|
|
|
|
|
* resident date-turnover routine to the proper handling of
|
|
|
|
|
* December 31 on leap years (when it is Day 366). That
|
|
|
|
|
* might have been left to the operator."
|
|
|
|
|
*
|
|
|
|
|
* Frederick Brooks, 'The Second-System Effect'.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <locale.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include "jstypes.h"
|
2025-02-05 12:40:54 +10:00
|
|
|
#include "jsstdint.h"
|
2018-09-08 18:08:48 +08:00
|
|
|
#include "jsprf.h"
|
|
|
|
|
#include "prmjtime.h"
|
2025-03-19 21:25:58 +10:00
|
|
|
#include "jsutil.h"
|
2018-09-08 18:08:48 +08:00
|
|
|
#include "jsapi.h"
|
2025-02-03 12:35:24 +10:00
|
|
|
#include "jsversion.h"
|
2025-02-05 12:40:54 +10:00
|
|
|
#include "jsbuiltins.h"
|
2018-09-08 18:08:48 +08:00
|
|
|
#include "jscntxt.h"
|
|
|
|
|
#include "jsdate.h"
|
|
|
|
|
#include "jsinterp.h"
|
|
|
|
|
#include "jsnum.h"
|
|
|
|
|
#include "jsobj.h"
|
|
|
|
|
#include "jsstr.h"
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
#include "jsobjinlines.h"
|
|
|
|
|
|
|
|
|
|
using namespace js;
|
|
|
|
|
|
2018-09-08 18:08:48 +08:00
|
|
|
/*
|
|
|
|
|
* The JS 'Date' object is patterned after the Java 'Date' object.
|
|
|
|
|
* Here is an script:
|
|
|
|
|
*
|
|
|
|
|
* today = new Date();
|
|
|
|
|
*
|
|
|
|
|
* print(today.toLocaleString());
|
|
|
|
|
*
|
|
|
|
|
* weekDay = today.getDay();
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* These Java (and ECMA-262) methods are supported:
|
|
|
|
|
*
|
|
|
|
|
* UTC
|
|
|
|
|
* getDate (getUTCDate)
|
|
|
|
|
* getDay (getUTCDay)
|
|
|
|
|
* getHours (getUTCHours)
|
|
|
|
|
* getMinutes (getUTCMinutes)
|
|
|
|
|
* getMonth (getUTCMonth)
|
|
|
|
|
* getSeconds (getUTCSeconds)
|
|
|
|
|
* getMilliseconds (getUTCMilliseconds)
|
|
|
|
|
* getTime
|
|
|
|
|
* getTimezoneOffset
|
|
|
|
|
* getYear
|
|
|
|
|
* getFullYear (getUTCFullYear)
|
|
|
|
|
* parse
|
|
|
|
|
* setDate (setUTCDate)
|
|
|
|
|
* setHours (setUTCHours)
|
|
|
|
|
* setMinutes (setUTCMinutes)
|
|
|
|
|
* setMonth (setUTCMonth)
|
|
|
|
|
* setSeconds (setUTCSeconds)
|
|
|
|
|
* setMilliseconds (setUTCMilliseconds)
|
|
|
|
|
* setTime
|
|
|
|
|
* setYear (setFullYear, setUTCFullYear)
|
|
|
|
|
* toGMTString (toUTCString)
|
|
|
|
|
* toLocaleString
|
|
|
|
|
* toString
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* These Java methods are not supported
|
|
|
|
|
*
|
|
|
|
|
* setDay
|
|
|
|
|
* before
|
|
|
|
|
* after
|
|
|
|
|
* equals
|
|
|
|
|
* hashCode
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language
|
|
|
|
|
* definition and reduce dependence on NSPR. NSPR is used to get the current
|
|
|
|
|
* time in milliseconds, the time zone offset, and the daylight savings time
|
|
|
|
|
* offset for a given time. NSPR is also used for Date.toLocaleString(), for
|
|
|
|
|
* locale-specific formatting, and to get a string representing the timezone.
|
|
|
|
|
* (Which turns out to be platform-dependent.)
|
|
|
|
|
*
|
|
|
|
|
* To do:
|
|
|
|
|
* (I did some performance tests by timing how long it took to run what
|
|
|
|
|
* I had of the js ECMA conformance tests.)
|
|
|
|
|
*
|
|
|
|
|
* - look at saving results across multiple calls to supporting
|
|
|
|
|
* functions; the toString functions compute some of the same values
|
|
|
|
|
* multiple times. Although - I took a quick stab at this, and I lost
|
|
|
|
|
* rather than gained. (Fractionally.) Hard to tell what compilers/processors
|
|
|
|
|
* are doing these days.
|
|
|
|
|
*
|
|
|
|
|
* - look at tweaking function return types to return double instead
|
|
|
|
|
* of int; this seems to make things run slightly faster sometimes.
|
|
|
|
|
* (though it could be architecture-dependent.) It'd be good to see
|
|
|
|
|
* how this does on win32. (Tried it on irix.) Types could use a
|
|
|
|
|
* general going-over.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Supporting functions - ECMA 15.9.1.*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define HoursPerDay 24.0
|
|
|
|
|
#define MinutesPerDay (HoursPerDay * MinutesPerHour)
|
|
|
|
|
#define MinutesPerHour 60.0
|
|
|
|
|
#define SecondsPerDay (MinutesPerDay * SecondsPerMinute)
|
|
|
|
|
#define SecondsPerHour (MinutesPerHour * SecondsPerMinute)
|
|
|
|
|
#define SecondsPerMinute 60.0
|
|
|
|
|
|
|
|
|
|
#if defined(XP_WIN) || defined(XP_OS2)
|
|
|
|
|
/* Work around msvc double optimization bug by making these runtime values; if
|
|
|
|
|
* they're available at compile time, msvc optimizes division by them by
|
|
|
|
|
* computing the reciprocal and multiplying instead of dividing - this loses
|
|
|
|
|
* when the reciprocal isn't representable in a double.
|
|
|
|
|
*/
|
|
|
|
|
static jsdouble msPerSecond = 1000.0;
|
|
|
|
|
static jsdouble msPerDay = SecondsPerDay * 1000.0;
|
|
|
|
|
static jsdouble msPerHour = SecondsPerHour * 1000.0;
|
|
|
|
|
static jsdouble msPerMinute = SecondsPerMinute * 1000.0;
|
|
|
|
|
#else
|
|
|
|
|
#define msPerDay (SecondsPerDay * msPerSecond)
|
|
|
|
|
#define msPerHour (SecondsPerHour * msPerSecond)
|
|
|
|
|
#define msPerMinute (SecondsPerMinute * msPerSecond)
|
|
|
|
|
#define msPerSecond 1000.0
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define Day(t) floor((t) / msPerDay)
|
|
|
|
|
|
|
|
|
|
static jsdouble
|
|
|
|
|
TimeWithinDay(jsdouble t)
|
|
|
|
|
{
|
|
|
|
|
jsdouble result;
|
|
|
|
|
result = fmod(t, msPerDay);
|
|
|
|
|
if (result < 0)
|
|
|
|
|
result += msPerDay;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
static inline bool
|
|
|
|
|
IsLeapYear(jsint year)
|
|
|
|
|
{
|
|
|
|
|
return year % 4 == 0 && (year % 100 || (year % 400 == 0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline jsint
|
|
|
|
|
DaysInYear(jsint year)
|
|
|
|
|
{
|
|
|
|
|
return IsLeapYear(year) ? 366 : 365;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline jsint
|
|
|
|
|
DaysInFebruary(jsint year)
|
|
|
|
|
{
|
|
|
|
|
return IsLeapYear(year) ? 29 : 28;
|
|
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* math here has to be f.p, because we need
|
|
|
|
|
* floor((1968 - 1969) / 4) == -1
|
|
|
|
|
*/
|
|
|
|
|
#define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \
|
|
|
|
|
- floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
|
|
|
|
|
#define TimeFromYear(y) (DayFromYear(y) * msPerDay)
|
|
|
|
|
|
|
|
|
|
static jsint
|
|
|
|
|
YearFromTime(jsdouble t)
|
|
|
|
|
{
|
|
|
|
|
jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970;
|
|
|
|
|
jsdouble t2 = (jsdouble) TimeFromYear(y);
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
/*
|
|
|
|
|
* Adjust the year if the approximation was wrong. Since the year was
|
|
|
|
|
* computed using the average number of ms per year, it will usually
|
|
|
|
|
* be wrong for dates within several hours of a year transition.
|
|
|
|
|
*/
|
2018-09-08 18:08:48 +08:00
|
|
|
if (t2 > t) {
|
|
|
|
|
y--;
|
|
|
|
|
} else {
|
|
|
|
|
if (t2 + msPerDay * DaysInYear(y) <= t)
|
|
|
|
|
y++;
|
|
|
|
|
}
|
|
|
|
|
return y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year)))
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The following array contains the day of year for the first day of
|
|
|
|
|
* each month, where index 0 is January, and day 0 is January 1.
|
|
|
|
|
*/
|
2025-02-05 12:40:54 +10:00
|
|
|
static jsdouble firstDayOfMonth[2][13] = {
|
|
|
|
|
{0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0, 365.0},
|
|
|
|
|
{0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0, 366.0}
|
2018-09-08 18:08:48 +08:00
|
|
|
};
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
#define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m]
|
|
|
|
|
|
|
|
|
|
static intN
|
|
|
|
|
DaysInMonth(jsint year, jsint month)
|
|
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSBool leap = IsLeapYear(year);
|
2025-02-05 12:40:54 +10:00
|
|
|
intN result = intN(DayFromMonth(month, leap) - DayFromMonth(month-1, leap));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
static intN
|
|
|
|
|
MonthFromTime(jsdouble t)
|
|
|
|
|
{
|
|
|
|
|
intN d, step;
|
|
|
|
|
jsint year = YearFromTime(t);
|
|
|
|
|
d = DayWithinYear(t, year);
|
|
|
|
|
|
|
|
|
|
if (d < (step = 31))
|
|
|
|
|
return 0;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (d < (step += DaysInFebruary(year)))
|
2018-09-08 18:08:48 +08:00
|
|
|
return 1;
|
|
|
|
|
if (d < (step += 31))
|
|
|
|
|
return 2;
|
|
|
|
|
if (d < (step += 30))
|
|
|
|
|
return 3;
|
|
|
|
|
if (d < (step += 31))
|
|
|
|
|
return 4;
|
|
|
|
|
if (d < (step += 30))
|
|
|
|
|
return 5;
|
|
|
|
|
if (d < (step += 31))
|
|
|
|
|
return 6;
|
|
|
|
|
if (d < (step += 31))
|
|
|
|
|
return 7;
|
|
|
|
|
if (d < (step += 30))
|
|
|
|
|
return 8;
|
|
|
|
|
if (d < (step += 31))
|
|
|
|
|
return 9;
|
|
|
|
|
if (d < (step += 30))
|
|
|
|
|
return 10;
|
|
|
|
|
return 11;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static intN
|
|
|
|
|
DateFromTime(jsdouble t)
|
|
|
|
|
{
|
|
|
|
|
intN d, step, next;
|
|
|
|
|
jsint year = YearFromTime(t);
|
|
|
|
|
d = DayWithinYear(t, year);
|
|
|
|
|
|
|
|
|
|
if (d <= (next = 30))
|
|
|
|
|
return d + 1;
|
|
|
|
|
step = next;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (d <= (next += DaysInFebruary(year)))
|
2018-09-08 18:08:48 +08:00
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
if (d <= (next += 31))
|
|
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
if (d <= (next += 30))
|
|
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
if (d <= (next += 31))
|
|
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
if (d <= (next += 30))
|
|
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
if (d <= (next += 31))
|
|
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
if (d <= (next += 31))
|
|
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
if (d <= (next += 30))
|
|
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
if (d <= (next += 31))
|
|
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
if (d <= (next += 30))
|
|
|
|
|
return d - step;
|
|
|
|
|
step = next;
|
|
|
|
|
return d - step;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static intN
|
|
|
|
|
WeekDay(jsdouble t)
|
|
|
|
|
{
|
|
|
|
|
jsint result;
|
|
|
|
|
result = (jsint) Day(t) + 4;
|
|
|
|
|
result = result % 7;
|
|
|
|
|
if (result < 0)
|
|
|
|
|
result += 7;
|
|
|
|
|
return (intN) result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define MakeTime(hour, min, sec, ms) \
|
|
|
|
|
((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms))
|
|
|
|
|
|
|
|
|
|
static jsdouble
|
|
|
|
|
MakeDay(jsdouble year, jsdouble month, jsdouble date)
|
|
|
|
|
{
|
|
|
|
|
JSBool leap;
|
|
|
|
|
jsdouble yearday;
|
|
|
|
|
jsdouble monthday;
|
|
|
|
|
|
|
|
|
|
year += floor(month / 12);
|
|
|
|
|
|
|
|
|
|
month = fmod(month, 12.0);
|
|
|
|
|
if (month < 0)
|
|
|
|
|
month += 12;
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
leap = IsLeapYear((jsint) year);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
yearday = floor(TimeFromYear(year) / msPerDay);
|
|
|
|
|
monthday = DayFromMonth(month, leap);
|
|
|
|
|
|
|
|
|
|
return yearday + monthday + date - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define MakeDate(day, time) ((day) * msPerDay + (time))
|
|
|
|
|
|
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
|
|
|
/*
|
|
|
|
|
* Years and leap years on which Jan 1 is a Sunday, Monday, etc.
|
2018-09-08 18:08:48 +08:00
|
|
|
*
|
|
|
|
|
* yearStartingWith[0][i] is an example non-leap year where
|
|
|
|
|
* Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
|
|
|
|
|
*
|
|
|
|
|
* yearStartingWith[1][i] is an example leap year where
|
|
|
|
|
* Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
|
|
|
|
|
*/
|
|
|
|
|
static jsint yearStartingWith[2][7] = {
|
|
|
|
|
{1978, 1973, 1974, 1975, 1981, 1971, 1977},
|
|
|
|
|
{1984, 1996, 1980, 1992, 1976, 1988, 1972}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Find a year for which any given date will fall on the same weekday.
|
|
|
|
|
*
|
|
|
|
|
* This function should be used with caution when used other than
|
|
|
|
|
* for determining DST; it hasn't been proven not to produce an
|
|
|
|
|
* incorrect year for times near year boundaries.
|
|
|
|
|
*/
|
|
|
|
|
static jsint
|
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
|
|
|
EquivalentYearForDST(jsint year)
|
|
|
|
|
{
|
2018-09-08 18:08:48 +08:00
|
|
|
jsint day;
|
|
|
|
|
|
|
|
|
|
day = (jsint) DayFromYear(year) + 4;
|
|
|
|
|
day = day % 7;
|
|
|
|
|
if (day < 0)
|
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
|
|
|
day += 7;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
return yearStartingWith[IsLeapYear(year)][day];
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* LocalTZA gets set by js_InitDateClass() */
|
|
|
|
|
static jsdouble LocalTZA;
|
|
|
|
|
|
|
|
|
|
static jsdouble
|
2025-02-05 12:40:54 +10:00
|
|
|
DaylightSavingTA(jsdouble t, JSContext *cx)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
/* abort if NaN */
|
|
|
|
|
if (JSDOUBLE_IS_NaN(t))
|
|
|
|
|
return t;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If earlier than 1970 or after 2038, potentially beyond the ken of
|
|
|
|
|
* many OSes, map it to an equivalent year before asking.
|
|
|
|
|
*/
|
|
|
|
|
if (t < 0.0 || t > 2145916800000.0) {
|
2025-02-05 12:40:54 +10:00
|
|
|
jsint year = EquivalentYearForDST(YearFromTime(t));
|
|
|
|
|
jsdouble day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
|
2018-09-08 18:08:48 +08:00
|
|
|
t = MakeDate(day, TimeWithinDay(t));
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
int64 timeMilliseconds = static_cast<int64>(t);
|
|
|
|
|
int64 offsetMilliseconds = cx->dstOffsetCache.getDSTOffsetMilliseconds(timeMilliseconds, cx);
|
|
|
|
|
return static_cast<jsdouble>(offsetMilliseconds);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
static jsdouble
|
|
|
|
|
AdjustTime(jsdouble date, JSContext *cx)
|
|
|
|
|
{
|
|
|
|
|
jsdouble t = DaylightSavingTA(date, cx) + LocalTZA;
|
|
|
|
|
t = (LocalTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
|
|
|
|
|
return t;
|
|
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
static jsdouble
|
|
|
|
|
LocalTime(jsdouble t, JSContext *cx)
|
|
|
|
|
{
|
|
|
|
|
return t + AdjustTime(t, cx);
|
|
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
static jsdouble
|
2025-02-05 12:40:54 +10:00
|
|
|
UTC(jsdouble t, JSContext *cx)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-02-05 12:40:54 +10:00
|
|
|
return t - AdjustTime(t - LocalTZA, cx);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static intN
|
|
|
|
|
HourFromTime(jsdouble t)
|
|
|
|
|
{
|
|
|
|
|
intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay);
|
|
|
|
|
if (result < 0)
|
|
|
|
|
result += (intN)HoursPerDay;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static intN
|
|
|
|
|
MinFromTime(jsdouble t)
|
|
|
|
|
{
|
|
|
|
|
intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour);
|
|
|
|
|
if (result < 0)
|
|
|
|
|
result += (intN)MinutesPerHour;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static intN
|
|
|
|
|
SecFromTime(jsdouble t)
|
|
|
|
|
{
|
|
|
|
|
intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute);
|
|
|
|
|
if (result < 0)
|
|
|
|
|
result += (intN)SecondsPerMinute;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static intN
|
|
|
|
|
msFromTime(jsdouble t)
|
|
|
|
|
{
|
|
|
|
|
intN result = (intN) fmod(t, msPerSecond);
|
|
|
|
|
if (result < 0)
|
|
|
|
|
result += (intN)msPerSecond;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* end of ECMA 'support' functions
|
|
|
|
|
*/
|
2025-02-03 12:35:24 +10:00
|
|
|
|
2018-09-08 18:08:48 +08:00
|
|
|
/*
|
|
|
|
|
* Other Support routines and definitions
|
|
|
|
|
*/
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
Class js_DateClass = {
|
2018-09-08 18:08:48 +08:00
|
|
|
js_Date_str,
|
2025-03-19 21:25:58 +10:00
|
|
|
JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) |
|
2023-07-12 13:27:26 +10:00
|
|
|
JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
|
2025-03-19 21:25:58 +10:00
|
|
|
PropertyStub, /* addProperty */
|
|
|
|
|
PropertyStub, /* delProperty */
|
|
|
|
|
PropertyStub, /* getProperty */
|
|
|
|
|
StrictPropertyStub, /* setProperty */
|
|
|
|
|
EnumerateStub,
|
|
|
|
|
ResolveStub,
|
|
|
|
|
ConvertStub
|
2018-09-08 18:08:48 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* for use by date_parse */
|
|
|
|
|
|
|
|
|
|
static const char* wtb[] = {
|
|
|
|
|
"am", "pm",
|
|
|
|
|
"monday", "tuesday", "wednesday", "thursday", "friday",
|
|
|
|
|
"saturday", "sunday",
|
|
|
|
|
"january", "february", "march", "april", "may", "june",
|
|
|
|
|
"july", "august", "september", "october", "november", "december",
|
|
|
|
|
"gmt", "ut", "utc",
|
|
|
|
|
"est", "edt",
|
|
|
|
|
"cst", "cdt",
|
|
|
|
|
"mst", "mdt",
|
|
|
|
|
"pst", "pdt"
|
|
|
|
|
/* time zone table needs to be expanded */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int ttb[] = {
|
|
|
|
|
-1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
|
|
|
|
|
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
|
|
|
|
10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
|
|
|
|
|
10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
|
|
|
|
|
10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
|
|
|
|
|
10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
|
|
|
|
|
10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* helper for date_parse */
|
|
|
|
|
static JSBool
|
|
|
|
|
date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
|
|
|
|
|
int count, int ignoreCase)
|
|
|
|
|
{
|
|
|
|
|
JSBool result = JS_FALSE;
|
|
|
|
|
/* return true if matches, otherwise, false */
|
|
|
|
|
|
|
|
|
|
while (count > 0 && s1[s1off] && s2[s2off]) {
|
|
|
|
|
if (ignoreCase) {
|
|
|
|
|
if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ((jschar)s1[s1off] != s2[s2off]) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s1off++;
|
|
|
|
|
s2off++;
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count == 0) {
|
|
|
|
|
result = JS_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find UTC time from given date... no 1900 correction! */
|
|
|
|
|
static jsdouble
|
|
|
|
|
date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour,
|
|
|
|
|
jsdouble min, jsdouble sec, jsdouble msec)
|
|
|
|
|
{
|
|
|
|
|
jsdouble day;
|
|
|
|
|
jsdouble msec_time;
|
|
|
|
|
jsdouble result;
|
|
|
|
|
|
|
|
|
|
day = MakeDay(year, mon, mday);
|
|
|
|
|
msec_time = MakeTime(hour, min, sec, msec);
|
|
|
|
|
result = MakeDate(day, msec_time);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2023-07-12 13:27:26 +10:00
|
|
|
|
|
|
|
|
/* compute the time in msec (unclipped) from the given args */
|
2018-09-08 18:08:48 +08:00
|
|
|
#define MAXARGS 7
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2018-09-08 18:08:48 +08:00
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_msecFromArgs(JSContext *cx, uintN argc, Value *argv, jsdouble *rval)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
uintN loop;
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble array[MAXARGS];
|
|
|
|
|
jsdouble msec_time;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
for (loop = 0; loop < MAXARGS; loop++) {
|
|
|
|
|
if (loop < argc) {
|
2025-02-05 12:40:54 +10:00
|
|
|
jsdouble d;
|
|
|
|
|
if (!ValueToNumber(cx, argv[loop], &d))
|
2018-09-08 18:08:48 +08:00
|
|
|
return JS_FALSE;
|
2023-07-12 13:27:26 +10:00
|
|
|
/* return NaN if any arg is not finite */
|
2018-09-08 18:08:48 +08:00
|
|
|
if (!JSDOUBLE_IS_FINITE(d)) {
|
2025-02-05 12:40:54 +10:00
|
|
|
*rval = js_NaN;
|
2023-07-12 13:27:26 +10:00
|
|
|
return JS_TRUE;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
2023-07-12 13:27:26 +10:00
|
|
|
array[loop] = js_DoubleToInteger(d);
|
2018-09-08 18:08:48 +08:00
|
|
|
} else {
|
2023-07-12 13:27:26 +10:00
|
|
|
if (loop == 2) {
|
|
|
|
|
array[loop] = 1; /* Default the date argument to 1. */
|
|
|
|
|
} else {
|
|
|
|
|
array[loop] = 0;
|
|
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* adjust 2-digit years into the 20th century */
|
|
|
|
|
if (array[0] >= 0 && array[0] <= 99)
|
|
|
|
|
array[0] += 1900;
|
|
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
msec_time = date_msecFromDate(array[0], array[1], array[2],
|
|
|
|
|
array[3], array[4], array[5], array[6]);
|
|
|
|
|
*rval = msec_time;
|
|
|
|
|
return JS_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* See ECMA 15.9.4.[3-10];
|
|
|
|
|
*/
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_UTC(JSContext *cx, uintN argc, Value *vp)
|
2023-07-12 13:27:26 +10:00
|
|
|
{
|
|
|
|
|
jsdouble msec_time;
|
|
|
|
|
|
|
|
|
|
if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time))
|
|
|
|
|
return JS_FALSE;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
msec_time = TIMECLIP(msec_time);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setNumber(msec_time);
|
|
|
|
|
return JS_TRUE;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
/*
|
|
|
|
|
* Read and convert decimal digits from s[*i] into *result
|
|
|
|
|
* while *i < limit.
|
|
|
|
|
*
|
|
|
|
|
* Succeed if any digits are converted. Advance *i only
|
|
|
|
|
* as digits are consumed.
|
|
|
|
|
*/
|
|
|
|
|
static JSBool
|
|
|
|
|
digits(size_t *result, const jschar *s, size_t *i, size_t limit)
|
|
|
|
|
{
|
|
|
|
|
size_t init = *i;
|
|
|
|
|
*result = 0;
|
|
|
|
|
while (*i < limit &&
|
|
|
|
|
('0' <= s[*i] && s[*i] <= '9')) {
|
|
|
|
|
*result *= 10;
|
|
|
|
|
*result += (s[*i] - '0');
|
|
|
|
|
++(*i);
|
|
|
|
|
}
|
|
|
|
|
return (*i != init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read and convert decimal digits to the right of a decimal point,
|
|
|
|
|
* representing a fractional integer, from s[*i] into *result
|
|
|
|
|
* while *i < limit.
|
|
|
|
|
*
|
|
|
|
|
* Succeed if any digits are converted. Advance *i only
|
|
|
|
|
* as digits are consumed.
|
|
|
|
|
*/
|
|
|
|
|
static JSBool
|
|
|
|
|
fractional(jsdouble *result, const jschar *s, size_t *i, size_t limit)
|
|
|
|
|
{
|
|
|
|
|
jsdouble factor = 0.1;
|
|
|
|
|
size_t init = *i;
|
|
|
|
|
*result = 0.0;
|
|
|
|
|
while (*i < limit &&
|
|
|
|
|
('0' <= s[*i] && s[*i] <= '9')) {
|
|
|
|
|
*result += (s[*i] - '0') * factor;
|
|
|
|
|
factor *= 0.1;
|
|
|
|
|
++(*i);
|
|
|
|
|
}
|
|
|
|
|
return (*i != init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read and convert exactly n decimal digits from s[*i]
|
|
|
|
|
* to s[min(*i+n,limit)] into *result.
|
|
|
|
|
*
|
|
|
|
|
* Succeed if exactly n digits are converted. Advance *i only
|
|
|
|
|
* on success.
|
|
|
|
|
*/
|
|
|
|
|
static JSBool
|
|
|
|
|
ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
|
|
|
|
|
{
|
|
|
|
|
size_t init = *i;
|
|
|
|
|
|
|
|
|
|
if (digits(result, s, i, JS_MIN(limit, init+n)))
|
|
|
|
|
return ((*i - init) == n);
|
|
|
|
|
|
|
|
|
|
*i = init;
|
|
|
|
|
return JS_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Parse a string in one of the date-time formats given by the W3C
|
|
|
|
|
* "NOTE-datetime" specification. These formats make up a restricted
|
|
|
|
|
* profile of the ISO 8601 format. Quoted here:
|
|
|
|
|
*
|
|
|
|
|
* The formats are as follows. Exactly the components shown here
|
|
|
|
|
* must be present, with exactly this punctuation. Note that the "T"
|
|
|
|
|
* appears literally in the string, to indicate the beginning of the
|
|
|
|
|
* time element, as specified in ISO 8601.
|
|
|
|
|
*
|
|
|
|
|
* Any combination of the date formats with the time formats is
|
|
|
|
|
* allowed, and also either the date or the time can be missing.
|
|
|
|
|
*
|
|
|
|
|
* The specification is silent on the meaning when fields are
|
|
|
|
|
* ommitted so the interpretations are a guess, but hopefully a
|
|
|
|
|
* reasonable one. We default the month to January, the day to the
|
|
|
|
|
* 1st, and hours minutes and seconds all to 0. If the date is
|
|
|
|
|
* missing entirely then we assume 1970-01-01 so that the time can
|
|
|
|
|
* be aded to a date later. If the time is missing then we assume
|
|
|
|
|
* 00:00 UTC. If the time is present but the time zone field is
|
|
|
|
|
* missing then we use local time.
|
|
|
|
|
*
|
|
|
|
|
* Date part:
|
|
|
|
|
*
|
|
|
|
|
* Year:
|
|
|
|
|
* YYYY (eg 1997)
|
|
|
|
|
*
|
|
|
|
|
* Year and month:
|
|
|
|
|
* YYYY-MM (eg 1997-07)
|
|
|
|
|
*
|
|
|
|
|
* Complete date:
|
|
|
|
|
* YYYY-MM-DD (eg 1997-07-16)
|
|
|
|
|
*
|
|
|
|
|
* Time part:
|
|
|
|
|
*
|
|
|
|
|
* Hours and minutes:
|
|
|
|
|
* Thh:mmTZD (eg T19:20+01:00)
|
|
|
|
|
*
|
|
|
|
|
* Hours, minutes and seconds:
|
|
|
|
|
* Thh:mm:ssTZD (eg T19:20:30+01:00)
|
|
|
|
|
*
|
|
|
|
|
* Hours, minutes, seconds and a decimal fraction of a second:
|
|
|
|
|
* Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
|
|
|
|
|
*
|
|
|
|
|
* where:
|
|
|
|
|
*
|
|
|
|
|
* YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY
|
|
|
|
|
* MM = two-digit month (01=January, etc.)
|
|
|
|
|
* DD = two-digit day of month (01 through 31)
|
|
|
|
|
* hh = two digits of hour (00 through 23) (am/pm NOT allowed)
|
|
|
|
|
* mm = two digits of minute (00 through 59)
|
|
|
|
|
* ss = two digits of second (00 through 59)
|
|
|
|
|
* s = one or more digits representing a decimal fraction of a second
|
|
|
|
|
* TZD = time zone designator (Z or +hh:mm or -hh:mm or missing for local)
|
|
|
|
|
*/
|
|
|
|
|
|
2018-09-08 18:08:48 +08:00
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx)
|
2025-02-05 12:40:54 +10:00
|
|
|
{
|
|
|
|
|
jsdouble msec;
|
|
|
|
|
|
|
|
|
|
const jschar *s;
|
|
|
|
|
size_t limit;
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
int tzMul = 1;
|
|
|
|
|
int dateMul = 1;
|
|
|
|
|
size_t year = 1970;
|
|
|
|
|
size_t month = 1;
|
|
|
|
|
size_t day = 1;
|
|
|
|
|
size_t hour = 0;
|
|
|
|
|
size_t min = 0;
|
|
|
|
|
size_t sec = 0;
|
|
|
|
|
jsdouble frac = 0;
|
|
|
|
|
bool isLocalTime = JS_FALSE;
|
|
|
|
|
size_t tzHour = 0;
|
|
|
|
|
size_t tzMin = 0;
|
|
|
|
|
|
|
|
|
|
#define PEEK(ch) (i < limit && s[i] == ch)
|
|
|
|
|
|
|
|
|
|
#define NEED(ch) \
|
|
|
|
|
JS_BEGIN_MACRO \
|
|
|
|
|
if (i >= limit || s[i] != ch) { goto syntax; } else { ++i; } \
|
|
|
|
|
JS_END_MACRO
|
|
|
|
|
|
|
|
|
|
#define DONE_DATE_UNLESS(ch) \
|
|
|
|
|
JS_BEGIN_MACRO \
|
|
|
|
|
if (i >= limit || s[i] != ch) { goto done_date; } else { ++i; } \
|
|
|
|
|
JS_END_MACRO
|
|
|
|
|
|
|
|
|
|
#define DONE_UNLESS(ch) \
|
|
|
|
|
JS_BEGIN_MACRO \
|
|
|
|
|
if (i >= limit || s[i] != ch) { goto done; } else { ++i; } \
|
|
|
|
|
JS_END_MACRO
|
|
|
|
|
|
|
|
|
|
#define NEED_NDIGITS(n, field) \
|
|
|
|
|
JS_BEGIN_MACRO \
|
|
|
|
|
if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \
|
|
|
|
|
JS_END_MACRO
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
s = str->chars();
|
|
|
|
|
limit = str->length();
|
2025-02-05 12:40:54 +10:00
|
|
|
|
|
|
|
|
if (PEEK('+') || PEEK('-')) {
|
|
|
|
|
if (PEEK('-'))
|
|
|
|
|
dateMul = -1;
|
|
|
|
|
++i;
|
|
|
|
|
NEED_NDIGITS(6, year);
|
|
|
|
|
} else if (!PEEK('T')) {
|
|
|
|
|
NEED_NDIGITS(4, year);
|
|
|
|
|
}
|
|
|
|
|
DONE_DATE_UNLESS('-');
|
|
|
|
|
NEED_NDIGITS(2, month);
|
|
|
|
|
DONE_DATE_UNLESS('-');
|
|
|
|
|
NEED_NDIGITS(2, day);
|
|
|
|
|
|
|
|
|
|
done_date:
|
|
|
|
|
DONE_UNLESS('T');
|
|
|
|
|
NEED_NDIGITS(2, hour);
|
|
|
|
|
NEED(':');
|
|
|
|
|
NEED_NDIGITS(2, min);
|
|
|
|
|
|
|
|
|
|
if (PEEK(':')) {
|
|
|
|
|
++i;
|
|
|
|
|
NEED_NDIGITS(2, sec);
|
|
|
|
|
if (PEEK('.')) {
|
|
|
|
|
++i;
|
|
|
|
|
if (!fractional(&frac, s, &i, limit))
|
|
|
|
|
goto syntax;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PEEK('Z')) {
|
|
|
|
|
++i;
|
|
|
|
|
} else if (PEEK('+') || PEEK('-')) {
|
|
|
|
|
if (PEEK('-'))
|
|
|
|
|
tzMul = -1;
|
|
|
|
|
++i;
|
|
|
|
|
NEED_NDIGITS(2, tzHour);
|
|
|
|
|
NEED(':');
|
|
|
|
|
NEED_NDIGITS(2, tzMin);
|
|
|
|
|
} else {
|
|
|
|
|
isLocalTime = JS_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
if (year > 275943 // ceil(1e8/365) + 1970
|
|
|
|
|
|| (month == 0 || month > 12)
|
|
|
|
|
|| (day == 0 || day > size_t(DaysInMonth(year,month)))
|
|
|
|
|
|| hour > 24
|
|
|
|
|
|| ((hour == 24) && (min > 0 || sec > 0))
|
|
|
|
|
|| min > 59
|
|
|
|
|
|| sec > 59
|
|
|
|
|
|| tzHour > 23
|
|
|
|
|
|| tzMin > 59)
|
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
|
|
if (i != limit)
|
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
|
|
month -= 1; /* convert month to 0-based */
|
|
|
|
|
|
|
|
|
|
msec = date_msecFromDate(dateMul * (jsdouble)year, month, day,
|
|
|
|
|
hour, min, sec,
|
|
|
|
|
frac * 1000.0);;
|
|
|
|
|
|
|
|
|
|
if (isLocalTime) {
|
|
|
|
|
msec = UTC(msec, cx);
|
|
|
|
|
} else {
|
|
|
|
|
msec -= ((tzMul) * ((tzHour * msPerHour)
|
|
|
|
|
+ (tzMin * msPerMinute)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (msec < -8.64e15 || msec > 8.64e15)
|
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
|
|
*result = msec;
|
|
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
|
|
syntax:
|
|
|
|
|
/* syntax error */
|
|
|
|
|
*result = 0;
|
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
|
|
#undef PEEK
|
|
|
|
|
#undef NEED
|
|
|
|
|
#undef DONE_UNLESS
|
|
|
|
|
#undef NEED_NDIGITS
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_parseString(JSLinearString *str, jsdouble *result, JSContext *cx)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
jsdouble msec;
|
|
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
const jschar *s;
|
|
|
|
|
size_t limit;
|
2018-09-08 18:08:48 +08:00
|
|
|
size_t i = 0;
|
|
|
|
|
int year = -1;
|
|
|
|
|
int mon = -1;
|
|
|
|
|
int mday = -1;
|
|
|
|
|
int hour = -1;
|
|
|
|
|
int min = -1;
|
|
|
|
|
int sec = -1;
|
|
|
|
|
int c = -1;
|
|
|
|
|
int n = -1;
|
2023-07-12 13:27:26 +10:00
|
|
|
int tzoffset = -1;
|
2018-09-08 18:08:48 +08:00
|
|
|
int prevc = 0;
|
|
|
|
|
JSBool seenplusminus = JS_FALSE;
|
|
|
|
|
int temp;
|
|
|
|
|
JSBool seenmonthname = JS_FALSE;
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
if (date_parseISOString(str, result, cx))
|
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
s = str->chars();
|
|
|
|
|
limit = str->length();
|
2018-09-08 18:08:48 +08:00
|
|
|
if (limit == 0)
|
|
|
|
|
goto syntax;
|
|
|
|
|
while (i < limit) {
|
|
|
|
|
c = s[i];
|
|
|
|
|
i++;
|
|
|
|
|
if (c <= ' ' || c == ',' || c == '-') {
|
|
|
|
|
if (c == '-' && '0' <= s[i] && s[i] <= '9') {
|
|
|
|
|
prevc = c;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (c == '(') { /* comments) */
|
|
|
|
|
int depth = 1;
|
|
|
|
|
while (i < limit) {
|
|
|
|
|
c = s[i];
|
|
|
|
|
i++;
|
|
|
|
|
if (c == '(') depth++;
|
|
|
|
|
else if (c == ')')
|
|
|
|
|
if (--depth <= 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if ('0' <= c && c <= '9') {
|
|
|
|
|
n = c - '0';
|
|
|
|
|
while (i < limit && '0' <= (c = s[i]) && c <= '9') {
|
|
|
|
|
n = n * 10 + c - '0';
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* allow TZA before the year, so
|
|
|
|
|
* 'Wed Nov 05 21:49:11 GMT-0800 1997'
|
|
|
|
|
* works */
|
|
|
|
|
|
|
|
|
|
/* uses of seenplusminus allow : in TZA, so Java
|
|
|
|
|
* no-timezone style of GMT+4:30 works
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
|
|
|
|
|
/* make ':' case below change tzoffset */
|
|
|
|
|
seenplusminus = JS_TRUE;
|
|
|
|
|
|
|
|
|
|
/* offset */
|
|
|
|
|
if (n < 24)
|
|
|
|
|
n = n * 60; /* EG. "GMT-3" */
|
|
|
|
|
else
|
|
|
|
|
n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
|
|
|
|
|
if (prevc == '+') /* plus means east of GMT */
|
|
|
|
|
n = -n;
|
|
|
|
|
if (tzoffset != 0 && tzoffset != -1)
|
|
|
|
|
goto syntax;
|
|
|
|
|
tzoffset = n;
|
|
|
|
|
} else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) {
|
|
|
|
|
if (c <= ' ' || c == ',' || c == '/' || i >= limit)
|
|
|
|
|
year = n;
|
|
|
|
|
else
|
|
|
|
|
goto syntax;
|
|
|
|
|
} else if (c == ':') {
|
|
|
|
|
if (hour < 0)
|
|
|
|
|
hour = /*byte*/ n;
|
|
|
|
|
else if (min < 0)
|
|
|
|
|
min = /*byte*/ n;
|
|
|
|
|
else
|
|
|
|
|
goto syntax;
|
|
|
|
|
} else if (c == '/') {
|
|
|
|
|
/* until it is determined that mon is the actual
|
|
|
|
|
month, keep it as 1-based rather than 0-based */
|
|
|
|
|
if (mon < 0)
|
|
|
|
|
mon = /*byte*/ n;
|
|
|
|
|
else if (mday < 0)
|
|
|
|
|
mday = /*byte*/ n;
|
|
|
|
|
else
|
|
|
|
|
goto syntax;
|
|
|
|
|
} else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') {
|
|
|
|
|
goto syntax;
|
|
|
|
|
} else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
|
|
|
|
|
if (tzoffset < 0)
|
|
|
|
|
tzoffset -= n;
|
|
|
|
|
else
|
|
|
|
|
tzoffset += n;
|
|
|
|
|
} else if (hour >= 0 && min < 0) {
|
|
|
|
|
min = /*byte*/ n;
|
|
|
|
|
} else if (prevc == ':' && min >= 0 && sec < 0) {
|
|
|
|
|
sec = /*byte*/ n;
|
|
|
|
|
} else if (mon < 0) {
|
|
|
|
|
mon = /*byte*/n;
|
|
|
|
|
} else if (mon >= 0 && mday < 0) {
|
|
|
|
|
mday = /*byte*/ n;
|
|
|
|
|
} else if (mon >= 0 && mday >= 0 && year < 0) {
|
|
|
|
|
year = n;
|
|
|
|
|
} else {
|
|
|
|
|
goto syntax;
|
|
|
|
|
}
|
|
|
|
|
prevc = 0;
|
|
|
|
|
} else if (c == '/' || c == ':' || c == '+' || c == '-') {
|
|
|
|
|
prevc = c;
|
|
|
|
|
} else {
|
|
|
|
|
size_t st = i - 1;
|
|
|
|
|
int k;
|
|
|
|
|
while (i < limit) {
|
|
|
|
|
c = s[i];
|
|
|
|
|
if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
|
|
|
|
|
break;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
if (i <= st + 1)
|
|
|
|
|
goto syntax;
|
2023-07-12 13:27:26 +10:00
|
|
|
for (k = JS_ARRAY_LENGTH(wtb); --k >= 0;)
|
2018-09-08 18:08:48 +08:00
|
|
|
if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
|
|
|
|
|
int action = ttb[k];
|
|
|
|
|
if (action != 0) {
|
|
|
|
|
if (action < 0) {
|
|
|
|
|
/*
|
|
|
|
|
* AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
|
|
|
|
|
* 12:30, instead of blindly adding 12 if PM.
|
|
|
|
|
*/
|
|
|
|
|
JS_ASSERT(action == -1 || action == -2);
|
|
|
|
|
if (hour > 12 || hour < 0) {
|
|
|
|
|
goto syntax;
|
|
|
|
|
} else {
|
|
|
|
|
if (action == -1 && hour == 12) { /* am */
|
|
|
|
|
hour = 0;
|
|
|
|
|
} else if (action == -2 && hour != 12) { /* pm */
|
|
|
|
|
hour += 12;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (action <= 13) { /* month! */
|
|
|
|
|
/* Adjust mon to be 1-based until the final values
|
|
|
|
|
for mon, mday and year are adjusted below */
|
|
|
|
|
if (seenmonthname) {
|
|
|
|
|
goto syntax;
|
|
|
|
|
}
|
|
|
|
|
seenmonthname = JS_TRUE;
|
|
|
|
|
temp = /*byte*/ (action - 2) + 1;
|
|
|
|
|
|
|
|
|
|
if (mon < 0) {
|
|
|
|
|
mon = temp;
|
|
|
|
|
} else if (mday < 0) {
|
|
|
|
|
mday = mon;
|
|
|
|
|
mon = temp;
|
|
|
|
|
} else if (year < 0) {
|
|
|
|
|
year = mon;
|
|
|
|
|
mon = temp;
|
|
|
|
|
} else {
|
|
|
|
|
goto syntax;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
tzoffset = action - 10000;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (k < 0)
|
|
|
|
|
goto syntax;
|
|
|
|
|
prevc = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (year < 0 || mon < 0 || mday < 0)
|
|
|
|
|
goto syntax;
|
|
|
|
|
/*
|
|
|
|
|
Case 1. The input string contains an English month name.
|
|
|
|
|
The form of the string can be month f l, or f month l, or
|
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
|
|
|
f l month which each evaluate to the same date.
|
2018-09-08 18:08:48 +08:00
|
|
|
If f and l are both greater than or equal to 70, or
|
|
|
|
|
both less than 70, the date is invalid.
|
|
|
|
|
The year is taken to be the greater of the values f, l.
|
|
|
|
|
If the year is greater than or equal to 70 and less than 100,
|
|
|
|
|
it is considered to be the number of years after 1900.
|
|
|
|
|
Case 2. The input string is of the form "f/m/l" where f, m and l are
|
|
|
|
|
integers, e.g. 7/16/45.
|
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
|
|
|
Adjust the mon, mday and year values to achieve 100% MSIE
|
2018-09-08 18:08:48 +08:00
|
|
|
compatibility.
|
|
|
|
|
a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
|
|
|
|
|
i. If year < 100, it is the number of years after 1900
|
|
|
|
|
ii. If year >= 100, it is the number of years after 0.
|
|
|
|
|
b. If 70 <= f < 100
|
|
|
|
|
i. If m < 70, f/m/l is interpreted as
|
|
|
|
|
year/month/day where year is the number of years after
|
|
|
|
|
1900.
|
|
|
|
|
ii. If m >= 70, the date is invalid.
|
|
|
|
|
c. If f >= 100
|
|
|
|
|
i. If m < 70, f/m/l is interpreted as
|
|
|
|
|
year/month/day where year is the number of years after 0.
|
|
|
|
|
ii. If m >= 70, the date is invalid.
|
|
|
|
|
*/
|
|
|
|
|
if (seenmonthname) {
|
|
|
|
|
if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) {
|
|
|
|
|
goto syntax;
|
|
|
|
|
}
|
|
|
|
|
if (mday > year) {
|
|
|
|
|
temp = year;
|
|
|
|
|
year = mday;
|
|
|
|
|
mday = temp;
|
|
|
|
|
}
|
|
|
|
|
if (year >= 70 && year < 100) {
|
|
|
|
|
year += 1900;
|
|
|
|
|
}
|
|
|
|
|
} else if (mon < 70) { /* (a) month/day/year */
|
|
|
|
|
if (year < 100) {
|
|
|
|
|
year += 1900;
|
|
|
|
|
}
|
|
|
|
|
} else if (mon < 100) { /* (b) year/month/day */
|
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
|
|
|
if (mday < 70) {
|
2018-09-08 18:08:48 +08:00
|
|
|
temp = year;
|
|
|
|
|
year = mon + 1900;
|
|
|
|
|
mon = mday;
|
|
|
|
|
mday = temp;
|
|
|
|
|
} else {
|
|
|
|
|
goto syntax;
|
|
|
|
|
}
|
|
|
|
|
} else { /* (c) year/month/day */
|
|
|
|
|
if (mday < 70) {
|
|
|
|
|
temp = year;
|
|
|
|
|
year = mon;
|
|
|
|
|
mon = mday;
|
|
|
|
|
mday = temp;
|
|
|
|
|
} else {
|
|
|
|
|
goto syntax;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mon -= 1; /* convert month to 0-based */
|
|
|
|
|
if (sec < 0)
|
|
|
|
|
sec = 0;
|
|
|
|
|
if (min < 0)
|
|
|
|
|
min = 0;
|
|
|
|
|
if (hour < 0)
|
|
|
|
|
hour = 0;
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
|
|
|
|
|
|
|
|
|
|
if (tzoffset == -1) { /* no time zone specified, have to use local */
|
|
|
|
|
msec = UTC(msec, cx);
|
|
|
|
|
} else {
|
|
|
|
|
msec += tzoffset * msPerMinute;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*result = msec;
|
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
|
|
syntax:
|
|
|
|
|
/* syntax error */
|
|
|
|
|
*result = 0;
|
|
|
|
|
return JS_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_parse(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
JSString *str;
|
|
|
|
|
jsdouble result;
|
|
|
|
|
|
2025-02-03 12:35:24 +10:00
|
|
|
if (argc == 0) {
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setDouble(js_NaN);
|
2025-02-05 12:40:54 +10:00
|
|
|
return true;
|
2025-02-03 12:35:24 +10:00
|
|
|
}
|
2023-07-12 13:27:26 +10:00
|
|
|
str = js_ValueToString(cx, vp[2]);
|
2018-09-08 18:08:48 +08:00
|
|
|
if (!str)
|
|
|
|
|
return JS_FALSE;
|
2025-03-19 21:25:58 +10:00
|
|
|
vp[2].setString(str);
|
|
|
|
|
JSLinearString *linearStr = str->ensureLinear(cx);
|
|
|
|
|
if (!linearStr)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!date_parseString(linearStr, &result, cx)) {
|
|
|
|
|
vp->setDouble(js_NaN);
|
2025-02-05 12:40:54 +10:00
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = TIMECLIP(result);
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
static inline jsdouble
|
|
|
|
|
NowAsMillis()
|
|
|
|
|
{
|
|
|
|
|
return (jsdouble) (PRMJ_Now() / PRMJ_USEC_PER_MSEC);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_now(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setDouble(NowAsMillis());
|
|
|
|
|
return JS_TRUE;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
#ifdef JS_TRACER
|
|
|
|
|
static jsdouble FASTCALL
|
|
|
|
|
date_now_tn(JSContext*)
|
|
|
|
|
{
|
|
|
|
|
return NowAsMillis();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-09-08 18:08:48 +08:00
|
|
|
/*
|
2023-07-12 13:27:26 +10:00
|
|
|
* Get UTC time from the date object. Returns false if the object is not
|
|
|
|
|
* Date type.
|
2018-09-08 18:08:48 +08:00
|
|
|
*/
|
2023-07-12 13:27:26 +10:00
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
|
2023-07-12 13:27:26 +10:00
|
|
|
return JS_FALSE;
|
2025-03-19 21:25:58 +10:00
|
|
|
*dp = obj->getDateUTCTime().toNumber();
|
2023-07-12 13:27:26 +10:00
|
|
|
return JS_TRUE;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
/*
|
2025-02-05 12:40:54 +10:00
|
|
|
* Set UTC time to a given time and invalidate cached local time.
|
2023-07-12 13:27:26 +10:00
|
|
|
*/
|
2018-09-08 18:08:48 +08:00
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JS_ASSERT(obj->isDate());
|
2025-02-05 12:40:54 +10:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
size_t slotCap = JS_MIN(obj->numSlots(), JSObject::DATE_CLASS_RESERVED_SLOTS);
|
|
|
|
|
for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; ind < slotCap; ind++)
|
|
|
|
|
obj->getSlotRef(ind).setUndefined();
|
|
|
|
|
|
|
|
|
|
obj->setDateUTCTime(DoubleValue(t));
|
2025-02-05 12:40:54 +10:00
|
|
|
if (vp)
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setDouble(t);
|
2025-02-05 12:40:54 +10:00
|
|
|
return true;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
static void
|
|
|
|
|
SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL)
|
|
|
|
|
{
|
|
|
|
|
jsdouble NaN = cx->runtime->NaNValue.getDoubleRef();
|
|
|
|
|
SetUTCTime(cx, obj, NaN, vp);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
/*
|
2025-03-19 21:25:58 +10:00
|
|
|
* Cache the local time, year, month, and so forth of the object.
|
|
|
|
|
* If UTC time is not finite (e.g., NaN), the local time
|
|
|
|
|
* slots will be set to the UTC time without conversion.
|
2023-07-12 13:27:26 +10:00
|
|
|
*/
|
2025-03-19 21:25:58 +10:00
|
|
|
static bool
|
|
|
|
|
FillLocalTimes(JSContext *cx, JSObject *obj)
|
2023-07-12 13:27:26 +10:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JS_ASSERT(obj->isDate());
|
|
|
|
|
|
|
|
|
|
jsdouble utcTime = obj->getDateUTCTime().toNumber();
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
/* Make sure there are slots to store the cached information. */
|
|
|
|
|
if (obj->numSlots() < JSObject::DATE_CLASS_RESERVED_SLOTS) {
|
|
|
|
|
if (!obj->growSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!JSDOUBLE_IS_FINITE(utcTime)) {
|
|
|
|
|
for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
|
|
|
|
|
ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
|
|
|
|
|
ind++) {
|
|
|
|
|
obj->setSlot(ind, DoubleValue(utcTime));
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
jsdouble localTime = LocalTime(utcTime, cx);
|
|
|
|
|
|
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime));
|
|
|
|
|
|
|
|
|
|
jsint year = (jsint) floor(localTime /(msPerDay*365.2425)) + 1970;
|
|
|
|
|
jsdouble yearStartTime = (jsdouble) TimeFromYear(year);
|
|
|
|
|
|
|
|
|
|
/* Adjust the year in case the approximation was wrong, as in YearFromTime. */
|
|
|
|
|
jsint yearDays;
|
|
|
|
|
if (yearStartTime > localTime) {
|
|
|
|
|
year--;
|
|
|
|
|
yearStartTime -= (msPerDay * DaysInYear(year));
|
|
|
|
|
yearDays = DaysInYear(year);
|
|
|
|
|
} else {
|
|
|
|
|
yearDays = DaysInYear(year);
|
|
|
|
|
jsdouble nextStart = yearStartTime + (msPerDay * yearDays);
|
|
|
|
|
if (nextStart <= localTime) {
|
|
|
|
|
year++;
|
|
|
|
|
yearStartTime = nextStart;
|
|
|
|
|
yearDays = DaysInYear(year);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR, Int32Value(year));
|
|
|
|
|
|
|
|
|
|
uint64 yearTime = uint64(localTime - yearStartTime);
|
|
|
|
|
jsint yearSeconds = uint32(yearTime / 1000);
|
|
|
|
|
|
|
|
|
|
jsint day = yearSeconds / jsint(SecondsPerDay);
|
|
|
|
|
|
|
|
|
|
jsint step = -1, next = 30;
|
|
|
|
|
jsint month;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
if (day <= next) {
|
|
|
|
|
month = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
next += ((yearDays == 366) ? 29 : 28);
|
|
|
|
|
if (day <= next) {
|
|
|
|
|
month = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
|
month = 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
if (day <= (next += 30)) {
|
|
|
|
|
month = 3;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
|
month = 4;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
if (day <= (next += 30)) {
|
|
|
|
|
month = 5;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
|
month = 6;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
|
month = 7;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
if (day <= (next += 30)) {
|
|
|
|
|
month = 8;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
|
month = 9;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
if (day <= (next += 30)) {
|
|
|
|
|
month = 10;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
step = next;
|
|
|
|
|
month = 11;
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH, Int32Value(month));
|
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DATE, Int32Value(day - step));
|
|
|
|
|
|
|
|
|
|
jsint weekday = WeekDay(localTime);
|
|
|
|
|
|
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DAY, Int32Value(weekday));
|
|
|
|
|
|
|
|
|
|
jsint seconds = yearSeconds % 60;
|
|
|
|
|
|
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS, Int32Value(seconds));
|
|
|
|
|
|
|
|
|
|
jsint minutes = (yearSeconds / 60) % 60;
|
|
|
|
|
|
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES, Int32Value(minutes));
|
|
|
|
|
|
|
|
|
|
jsint hours = (yearSeconds / (60 * 60)) % 24;
|
|
|
|
|
|
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Cache the local times in obj, if necessary. */
|
|
|
|
|
static inline JSBool
|
|
|
|
|
GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = NULL)
|
|
|
|
|
{
|
|
|
|
|
if (!obj || !InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
|
|
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
/* If the local time is undefined, we need to fill in the cached values. */
|
|
|
|
|
if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
|
|
|
|
|
if (!FillLocalTimes(cx, obj))
|
2025-02-05 12:40:54 +10:00
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (time)
|
|
|
|
|
*time = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble();
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
return true;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
static inline bool
|
|
|
|
|
GetThisUTCTime(JSContext *cx, Value *vp, jsdouble *dp)
|
|
|
|
|
{
|
|
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
return GetUTCTime(cx, obj, vp, dp);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
/*
|
|
|
|
|
* See ECMA 15.9.5.4 thru 15.9.5.23
|
|
|
|
|
*/
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getTime(JSContext *cx, uintN argc, Value *vp)
|
2023-07-12 13:27:26 +10:00
|
|
|
{
|
|
|
|
|
jsdouble result;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &result))
|
|
|
|
|
return false;
|
|
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getYear(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, vp))
|
|
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
|
|
|
|
if (yearVal.isInt32()) {
|
2023-07-12 13:27:26 +10:00
|
|
|
/* Follow ECMA-262 to the letter, contrary to IE JScript. */
|
2025-03-19 21:25:58 +10:00
|
|
|
jsint year = yearVal.toInt32() - 1900;
|
|
|
|
|
vp->setInt32(year);
|
|
|
|
|
} else {
|
|
|
|
|
*vp = yearVal;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
return true;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getFullYear(JSContext *cx, uintN argc, Value *vp)
|
2023-07-12 13:27:26 +10:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, vp))
|
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
|
|
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
|
|
|
|
return JS_TRUE;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getUTCFullYear(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
jsdouble result;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &result))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (JSDOUBLE_IS_FINITE(result))
|
|
|
|
|
result = YearFromTime(result);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getMonth(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, vp))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getUTCMonth(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
jsdouble result;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &result))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (JSDOUBLE_IS_FINITE(result))
|
|
|
|
|
result = MonthFromTime(result);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getDate(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, vp))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getUTCDate(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
jsdouble result;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &result))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (JSDOUBLE_IS_FINITE(result))
|
|
|
|
|
result = DateFromTime(result);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getDay(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, vp))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getUTCDay(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
jsdouble result;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &result))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (JSDOUBLE_IS_FINITE(result))
|
|
|
|
|
result = WeekDay(result);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getHours(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, vp))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getUTCHours(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
jsdouble result;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &result))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (JSDOUBLE_IS_FINITE(result))
|
|
|
|
|
result = HourFromTime(result);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setNumber(result);
|
|
|
|
|
return JS_TRUE;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getMinutes(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, vp))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
jsdouble result;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &result))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (JSDOUBLE_IS_FINITE(result))
|
|
|
|
|
result = MinFromTime(result);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Date.getSeconds is mapped to getUTCSeconds */
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getUTCSeconds(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, vp))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Date.getMilliseconds is mapped to getUTCMilliseconds */
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getUTCMilliseconds(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
jsdouble result;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &result))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (JSDOUBLE_IS_FINITE(result))
|
|
|
|
|
result = msFromTime(result);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_getTimezoneOffset(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
jsdouble utctime;
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetUTCTime(cx, obj, vp, &utctime))
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
jsdouble localtime;
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime))
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/*
|
2023-07-12 13:27:26 +10:00
|
|
|
* Return the time zone offset in minutes for the current locale that is
|
|
|
|
|
* appropriate for this time. This value would be a constant except for
|
|
|
|
|
* daylight savings time.
|
2018-09-08 18:08:48 +08:00
|
|
|
*/
|
2025-03-19 21:25:58 +10:00
|
|
|
jsdouble result = (utctime - localtime) / msPerMinute;
|
|
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setTime(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!InstanceOf(cx, obj, &js_DateClass, vp + 2))
|
2025-02-05 12:40:54 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
if (argc == 0) {
|
|
|
|
|
SetDateToNaN(cx, obj, vp);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
jsdouble result;
|
|
|
|
|
if (!ValueToNumber(cx, vp[2], &result))
|
|
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
return SetUTCTime(cx, obj, TIMECLIP(result), vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
Value *argv;
|
2018-09-08 18:08:48 +08:00
|
|
|
uintN i;
|
|
|
|
|
jsdouble args[4], *argp, *stop;
|
|
|
|
|
jsdouble hour, min, sec, msec;
|
|
|
|
|
jsdouble lorutime; /* Local or UTC version of *date */
|
|
|
|
|
|
|
|
|
|
jsdouble msec_time;
|
|
|
|
|
jsdouble result;
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetUTCTime(cx, obj, vp, &result))
|
2025-02-05 12:40:54 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* just return NaN if the date is already NaN */
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!JSDOUBLE_IS_FINITE(result)) {
|
|
|
|
|
vp->setNumber(result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
/*
|
|
|
|
|
* Satisfy the ECMA rule that if a function is called with
|
2018-09-08 18:08:48 +08:00
|
|
|
* fewer arguments than the specified formal arguments, the
|
|
|
|
|
* remaining arguments are set to undefined. Seems like all
|
|
|
|
|
* the Date.setWhatever functions in ECMA are only varargs
|
|
|
|
|
* beyond the first argument; this should be set to undefined
|
|
|
|
|
* if it's not given. This means that "d = new Date();
|
|
|
|
|
* d.setMilliseconds()" returns NaN. Blech.
|
|
|
|
|
*/
|
2025-02-05 12:40:54 +10:00
|
|
|
if (argc == 0) {
|
|
|
|
|
SetDateToNaN(cx, obj, vp);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2025-02-03 12:35:24 +10:00
|
|
|
if (argc > maxargs)
|
2018-09-08 18:08:48 +08:00
|
|
|
argc = maxargs; /* clamp argc */
|
2025-02-03 12:35:24 +10:00
|
|
|
JS_ASSERT(argc <= 4);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
argv = vp + 2;
|
2018-09-08 18:08:48 +08:00
|
|
|
for (i = 0; i < argc; i++) {
|
2025-02-05 12:40:54 +10:00
|
|
|
if (!ValueToNumber(cx, argv[i], &args[i]))
|
|
|
|
|
return false;
|
|
|
|
|
if (!JSDOUBLE_IS_FINITE(args[i])) {
|
|
|
|
|
SetDateToNaN(cx, obj, vp);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
args[i] = js_DoubleToInteger(args[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (local)
|
2025-02-05 12:40:54 +10:00
|
|
|
lorutime = LocalTime(result, cx);
|
2018-09-08 18:08:48 +08:00
|
|
|
else
|
|
|
|
|
lorutime = result;
|
|
|
|
|
|
|
|
|
|
argp = args;
|
|
|
|
|
stop = argp + argc;
|
|
|
|
|
if (maxargs >= 4 && argp < stop)
|
|
|
|
|
hour = *argp++;
|
|
|
|
|
else
|
|
|
|
|
hour = HourFromTime(lorutime);
|
|
|
|
|
|
|
|
|
|
if (maxargs >= 3 && argp < stop)
|
|
|
|
|
min = *argp++;
|
|
|
|
|
else
|
|
|
|
|
min = MinFromTime(lorutime);
|
|
|
|
|
|
|
|
|
|
if (maxargs >= 2 && argp < stop)
|
|
|
|
|
sec = *argp++;
|
|
|
|
|
else
|
|
|
|
|
sec = SecFromTime(lorutime);
|
|
|
|
|
|
|
|
|
|
if (maxargs >= 1 && argp < stop)
|
|
|
|
|
msec = *argp;
|
|
|
|
|
else
|
|
|
|
|
msec = msFromTime(lorutime);
|
|
|
|
|
|
|
|
|
|
msec_time = MakeTime(hour, min, sec, msec);
|
|
|
|
|
result = MakeDate(Day(lorutime), msec_time);
|
|
|
|
|
|
|
|
|
|
/* fprintf(stderr, "%f\n", result); */
|
|
|
|
|
|
|
|
|
|
if (local)
|
2025-02-05 12:40:54 +10:00
|
|
|
result = UTC(result, cx);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* fprintf(stderr, "%f\n", result); */
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
return SetUTCTime(cx, obj, TIMECLIP(result), vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setMilliseconds(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeTime(cx, 1, JS_TRUE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setUTCMilliseconds(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeTime(cx, 1, JS_FALSE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setSeconds(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeTime(cx, 2, JS_TRUE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setUTCSeconds(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeTime(cx, 2, JS_FALSE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setMinutes(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeTime(cx, 3, JS_TRUE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setUTCMinutes(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeTime(cx, 3, JS_FALSE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setHours(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeTime(cx, 4, JS_TRUE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setUTCHours(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeTime(cx, 4, JS_FALSE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
Value *argv;
|
2018-09-08 18:08:48 +08:00
|
|
|
uintN i;
|
|
|
|
|
jsdouble lorutime; /* local or UTC version of *date */
|
|
|
|
|
jsdouble args[3], *argp, *stop;
|
|
|
|
|
jsdouble year, month, day;
|
|
|
|
|
jsdouble result;
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetUTCTime(cx, obj, vp, &result))
|
2025-02-05 12:40:54 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* see complaint about ECMA in date_MakeTime */
|
2025-02-05 12:40:54 +10:00
|
|
|
if (argc == 0) {
|
|
|
|
|
SetDateToNaN(cx, obj, vp);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2025-02-03 12:35:24 +10:00
|
|
|
if (argc > maxargs)
|
2018-09-08 18:08:48 +08:00
|
|
|
argc = maxargs; /* clamp argc */
|
2023-07-12 13:27:26 +10:00
|
|
|
JS_ASSERT(1 <= argc && argc <= 3);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
argv = vp + 2;
|
2018-09-08 18:08:48 +08:00
|
|
|
for (i = 0; i < argc; i++) {
|
2025-02-05 12:40:54 +10:00
|
|
|
if (!ValueToNumber(cx, argv[i], &args[i]))
|
2018-09-08 18:08:48 +08:00
|
|
|
return JS_FALSE;
|
2025-02-05 12:40:54 +10:00
|
|
|
if (!JSDOUBLE_IS_FINITE(args[i])) {
|
|
|
|
|
SetDateToNaN(cx, obj, vp);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
args[i] = js_DoubleToInteger(args[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* return NaN if date is NaN and we're not setting the year,
|
|
|
|
|
* If we are, use 0 as the time. */
|
|
|
|
|
if (!(JSDOUBLE_IS_FINITE(result))) {
|
2025-03-19 21:25:58 +10:00
|
|
|
if (maxargs < 3) {
|
|
|
|
|
vp->setDouble(result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-07-12 13:27:26 +10:00
|
|
|
lorutime = +0.;
|
2018-09-08 18:08:48 +08:00
|
|
|
} else {
|
2025-02-05 12:40:54 +10:00
|
|
|
lorutime = local ? LocalTime(result, cx) : result;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argp = args;
|
|
|
|
|
stop = argp + argc;
|
|
|
|
|
if (maxargs >= 3 && argp < stop)
|
|
|
|
|
year = *argp++;
|
|
|
|
|
else
|
|
|
|
|
year = YearFromTime(lorutime);
|
|
|
|
|
|
|
|
|
|
if (maxargs >= 2 && argp < stop)
|
|
|
|
|
month = *argp++;
|
|
|
|
|
else
|
|
|
|
|
month = MonthFromTime(lorutime);
|
|
|
|
|
|
|
|
|
|
if (maxargs >= 1 && argp < stop)
|
|
|
|
|
day = *argp++;
|
|
|
|
|
else
|
|
|
|
|
day = DateFromTime(lorutime);
|
|
|
|
|
|
|
|
|
|
day = MakeDay(year, month, day); /* day within year */
|
|
|
|
|
result = MakeDate(day, TimeWithinDay(lorutime));
|
|
|
|
|
|
|
|
|
|
if (local)
|
2025-02-05 12:40:54 +10:00
|
|
|
result = UTC(result, cx);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
return SetUTCTime(cx, obj, TIMECLIP(result), vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setDate(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeDate(cx, 1, JS_TRUE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setUTCDate(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeDate(cx, 1, JS_FALSE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setMonth(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeDate(cx, 2, JS_TRUE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setUTCMonth(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeDate(cx, 2, JS_FALSE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setFullYear(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeDate(cx, 3, JS_TRUE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setUTCFullYear(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_makeDate(cx, 3, JS_FALSE, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_setYear(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
jsdouble result;
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetUTCTime(cx, obj, vp, &result))
|
2025-02-05 12:40:54 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
if (argc == 0) {
|
|
|
|
|
/* Call this only after GetUTCTime has verified that obj is Date. */
|
|
|
|
|
SetDateToNaN(cx, obj, vp);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
jsdouble year;
|
|
|
|
|
if (!ValueToNumber(cx, vp[2], &year))
|
|
|
|
|
return false;
|
|
|
|
|
if (!JSDOUBLE_IS_FINITE(year)) {
|
|
|
|
|
SetDateToNaN(cx, obj, vp);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
year = js_DoubleToInteger(year);
|
2018-09-08 18:08:48 +08:00
|
|
|
if (year >= 0 && year <= 99)
|
|
|
|
|
year += 1900;
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
jsdouble t = JSDOUBLE_IS_FINITE(result) ? LocalTime(result, cx) : +0.0;
|
|
|
|
|
jsdouble day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
|
2018-09-08 18:08:48 +08:00
|
|
|
result = MakeDate(day, TimeWithinDay(t));
|
2025-02-05 12:40:54 +10:00
|
|
|
result = UTC(result, cx);
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
return SetUTCTime(cx, obj, TIMECLIP(result), vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* constants for toString, toUTCString */
|
|
|
|
|
static char js_NaN_date_str[] = "Invalid Date";
|
|
|
|
|
static const char* days[] =
|
|
|
|
|
{
|
|
|
|
|
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
|
|
|
|
|
};
|
|
|
|
|
static const char* months[] =
|
|
|
|
|
{
|
|
|
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
|
|
|
|
|
// Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
|
|
|
|
|
// requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
|
|
|
|
|
static void
|
|
|
|
|
print_gmt_string(char* buf, size_t size, jsdouble utctime)
|
|
|
|
|
{
|
|
|
|
|
JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
|
|
|
|
|
days[WeekDay(utctime)],
|
|
|
|
|
DateFromTime(utctime),
|
|
|
|
|
months[MonthFromTime(utctime)],
|
|
|
|
|
YearFromTime(utctime),
|
|
|
|
|
HourFromTime(utctime),
|
|
|
|
|
MinFromTime(utctime),
|
|
|
|
|
SecFromTime(utctime));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_iso_string(char* buf, size_t size, jsdouble utctime)
|
|
|
|
|
{
|
|
|
|
|
JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
|
|
|
|
|
YearFromTime(utctime),
|
|
|
|
|
MonthFromTime(utctime) + 1,
|
|
|
|
|
DateFromTime(utctime),
|
|
|
|
|
HourFromTime(utctime),
|
|
|
|
|
MinFromTime(utctime),
|
|
|
|
|
SecFromTime(utctime),
|
|
|
|
|
msFromTime(utctime));
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-08 18:08:48 +08:00
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_utc_format(JSContext *cx, Value *vp,
|
2025-02-05 12:40:54 +10:00
|
|
|
void (*printFunc)(char*, size_t, jsdouble))
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble utctime;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &utctime))
|
|
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
char buf[100];
|
|
|
|
|
if (!JSDOUBLE_IS_FINITE(utctime))
|
2018-09-08 18:08:48 +08:00
|
|
|
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
|
2025-03-19 21:25:58 +10:00
|
|
|
else
|
2025-02-05 12:40:54 +10:00
|
|
|
(*printFunc)(buf, sizeof buf, utctime);
|
2025-03-19 21:25:58 +10:00
|
|
|
|
|
|
|
|
JSString *str = JS_NewStringCopyZ(cx, buf);
|
2018-09-08 18:08:48 +08:00
|
|
|
if (!str)
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
|
|
|
|
vp->setString(str);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toGMTString(JSContext *cx, uintN argc, Value *vp)
|
2025-02-05 12:40:54 +10:00
|
|
|
{
|
|
|
|
|
return date_utc_format(cx, vp, print_gmt_string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toISOString(JSContext *cx, uintN argc, Value *vp)
|
2025-02-05 12:40:54 +10:00
|
|
|
{
|
|
|
|
|
return date_utc_format(cx, vp, print_iso_string);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
/* ES5 15.9.5.44. */
|
|
|
|
|
static JSBool
|
|
|
|
|
date_toJSON(JSContext *cx, uintN argc, Value *vp)
|
|
|
|
|
{
|
|
|
|
|
/* Step 1. */
|
|
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
|
Value &tv = vp[0];
|
|
|
|
|
if (!DefaultValue(cx, obj, JSTYPE_NUMBER, &tv))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
|
if (tv.isDouble() && !JSDOUBLE_IS_FINITE(tv.toDouble())) {
|
|
|
|
|
vp->setNull();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
|
Value &toISO = vp[0];
|
|
|
|
|
if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.toISOStringAtom), &toISO))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
|
if (!js_IsCallable(toISO)) {
|
|
|
|
|
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
|
|
|
|
|
JSMSG_BAD_TOISOSTRING_PROP);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Step 6. */
|
|
|
|
|
LeaveTrace(cx);
|
|
|
|
|
InvokeArgsGuard args;
|
|
|
|
|
if (!cx->stack().pushInvokeArgs(cx, 0, &args))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
args.callee() = toISO;
|
|
|
|
|
args.thisv().setObject(*obj);
|
|
|
|
|
|
|
|
|
|
if (!Invoke(cx, args, 0))
|
|
|
|
|
return false;
|
|
|
|
|
*vp = args.rval();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-08 18:08:48 +08:00
|
|
|
/* for Date.toLocaleString; interface to PRMJTime date struct.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2025-02-05 12:40:54 +10:00
|
|
|
new_explode(jsdouble timeval, PRMJTime *split, JSContext *cx)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
jsint year = YearFromTime(timeval);
|
|
|
|
|
|
|
|
|
|
split->tm_usec = (int32) msFromTime(timeval) * 1000;
|
|
|
|
|
split->tm_sec = (int8) SecFromTime(timeval);
|
|
|
|
|
split->tm_min = (int8) MinFromTime(timeval);
|
|
|
|
|
split->tm_hour = (int8) HourFromTime(timeval);
|
|
|
|
|
split->tm_mday = (int8) DateFromTime(timeval);
|
|
|
|
|
split->tm_mon = (int8) MonthFromTime(timeval);
|
|
|
|
|
split->tm_wday = (int8) WeekDay(timeval);
|
2023-07-12 13:27:26 +10:00
|
|
|
split->tm_year = year;
|
2018-09-08 18:08:48 +08:00
|
|
|
split->tm_yday = (int16) DayWithinYear(timeval, year);
|
|
|
|
|
|
|
|
|
|
/* not sure how this affects things, but it doesn't seem
|
|
|
|
|
to matter. */
|
2025-02-05 12:40:54 +10:00
|
|
|
split->tm_isdst = (DaylightSavingTA(timeval, cx) != 0);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef enum formatspec {
|
|
|
|
|
FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
|
|
|
|
|
} formatspec;
|
|
|
|
|
|
|
|
|
|
/* helper function */
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_format(JSContext *cx, jsdouble date, formatspec format, Value *rval)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
char buf[100];
|
|
|
|
|
JSString *str;
|
|
|
|
|
char tzbuf[100];
|
|
|
|
|
JSBool usetz;
|
|
|
|
|
size_t i, tzlen;
|
|
|
|
|
PRMJTime split;
|
|
|
|
|
|
|
|
|
|
if (!JSDOUBLE_IS_FINITE(date)) {
|
|
|
|
|
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
|
|
|
|
|
} else {
|
2025-02-05 12:40:54 +10:00
|
|
|
jsdouble local = LocalTime(date, cx);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* offset from GMT in minutes. The offset includes daylight savings,
|
|
|
|
|
if it applies. */
|
2025-02-05 12:40:54 +10:00
|
|
|
jsint minutes = (jsint) floor(AdjustTime(date, cx) / msPerMinute);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* map 510 minutes to 0830 hours */
|
|
|
|
|
intN offset = (minutes / 60) * 100 + minutes % 60;
|
|
|
|
|
|
|
|
|
|
/* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
|
|
|
|
|
* printed as 'GMT-0800' rather than as 'PST' to avoid
|
|
|
|
|
* operating-system dependence on strftime (which
|
|
|
|
|
* PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
|
|
|
|
|
* PST as 'Pacific Standard Time.' This way we always know
|
|
|
|
|
* what we're getting, and can parse it if we produce it.
|
|
|
|
|
* The OS TZA string is included as a comment.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* get a timezone string from the OS to include as a
|
|
|
|
|
comment. */
|
2025-02-05 12:40:54 +10:00
|
|
|
new_explode(date, &split, cx);
|
2018-09-08 18:08:48 +08:00
|
|
|
if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
|
|
|
|
|
|
|
|
|
|
/* Decide whether to use the resulting timezone string.
|
|
|
|
|
*
|
|
|
|
|
* Reject it if it contains any non-ASCII, non-alphanumeric
|
|
|
|
|
* characters. It's then likely in some other character
|
|
|
|
|
* encoding, and we probably won't display it correctly.
|
|
|
|
|
*/
|
|
|
|
|
usetz = JS_TRUE;
|
|
|
|
|
tzlen = strlen(tzbuf);
|
|
|
|
|
if (tzlen > 100) {
|
|
|
|
|
usetz = JS_FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
for (i = 0; i < tzlen; i++) {
|
|
|
|
|
jschar c = tzbuf[i];
|
|
|
|
|
if (c > 127 ||
|
|
|
|
|
!(isalpha(c) || isdigit(c) ||
|
|
|
|
|
c == ' ' || c == '(' || c == ')')) {
|
|
|
|
|
usetz = JS_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Also reject it if it's not parenthesized or if it's '()'. */
|
|
|
|
|
if (tzbuf[0] != '(' || tzbuf[1] == ')')
|
|
|
|
|
usetz = JS_FALSE;
|
|
|
|
|
} else
|
|
|
|
|
usetz = JS_FALSE;
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
|
case FORMATSPEC_FULL:
|
|
|
|
|
/*
|
|
|
|
|
* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
|
|
|
|
|
* requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
|
|
|
|
|
*/
|
|
|
|
|
/* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
|
|
|
|
|
JS_snprintf(buf, sizeof buf,
|
|
|
|
|
"%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
|
|
|
|
|
days[WeekDay(local)],
|
|
|
|
|
months[MonthFromTime(local)],
|
|
|
|
|
DateFromTime(local),
|
|
|
|
|
YearFromTime(local),
|
|
|
|
|
HourFromTime(local),
|
|
|
|
|
MinFromTime(local),
|
|
|
|
|
SecFromTime(local),
|
|
|
|
|
offset,
|
|
|
|
|
usetz ? " " : "",
|
|
|
|
|
usetz ? tzbuf : "");
|
|
|
|
|
break;
|
|
|
|
|
case FORMATSPEC_DATE:
|
|
|
|
|
/* Tue Oct 31 2000 */
|
|
|
|
|
JS_snprintf(buf, sizeof buf,
|
|
|
|
|
"%s %s %.2d %.4d",
|
|
|
|
|
days[WeekDay(local)],
|
|
|
|
|
months[MonthFromTime(local)],
|
|
|
|
|
DateFromTime(local),
|
|
|
|
|
YearFromTime(local));
|
|
|
|
|
break;
|
|
|
|
|
case FORMATSPEC_TIME:
|
|
|
|
|
/* 09:41:40 GMT-0800 (PST) */
|
|
|
|
|
JS_snprintf(buf, sizeof buf,
|
|
|
|
|
"%.2d:%.2d:%.2d GMT%+.4d%s%s",
|
|
|
|
|
HourFromTime(local),
|
|
|
|
|
MinFromTime(local),
|
|
|
|
|
SecFromTime(local),
|
|
|
|
|
offset,
|
|
|
|
|
usetz ? " " : "",
|
|
|
|
|
usetz ? tzbuf : "");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str = JS_NewStringCopyZ(cx, buf);
|
|
|
|
|
if (!str)
|
|
|
|
|
return JS_FALSE;
|
2025-03-19 21:25:58 +10:00
|
|
|
rval->setString(str);
|
2018-09-08 18:08:48 +08:00
|
|
|
return JS_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toLocaleHelper(JSContext *cx, JSObject *obj, const char *format, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
char buf[100];
|
|
|
|
|
JSString *str;
|
|
|
|
|
PRMJTime split;
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble utctime;
|
|
|
|
|
|
|
|
|
|
if (!GetUTCTime(cx, obj, vp, &utctime))
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!JSDOUBLE_IS_FINITE(utctime)) {
|
2018-09-08 18:08:48 +08:00
|
|
|
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
|
|
|
|
|
} else {
|
|
|
|
|
intN result_len;
|
2025-02-05 12:40:54 +10:00
|
|
|
jsdouble local = LocalTime(utctime, cx);
|
|
|
|
|
new_explode(local, &split, cx);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* let PRMJTime format it. */
|
|
|
|
|
result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
|
|
|
|
|
|
|
|
|
|
/* If it failed, default to toString. */
|
|
|
|
|
if (result_len == 0)
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_format(cx, utctime, FORMATSPEC_FULL, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* Hacked check against undesired 2-digit year 00/00/00 form. */
|
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
|
|
|
if (strcmp(format, "%x") == 0 && result_len >= 6 &&
|
|
|
|
|
/* Format %x means use OS settings, which may have 2-digit yr, so
|
|
|
|
|
hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
|
|
|
|
|
!isdigit(buf[result_len - 3]) &&
|
|
|
|
|
isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
|
|
|
|
|
/* ...but not if starts with 4-digit year, like 2022/3/11. */
|
|
|
|
|
!(isdigit(buf[0]) && isdigit(buf[1]) &&
|
|
|
|
|
isdigit(buf[2]) && isdigit(buf[3]))) {
|
2018-09-08 18:08:48 +08:00
|
|
|
JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
|
|
|
|
|
"%d", js_DateGetYear(cx, obj));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
|
2025-03-19 21:25:58 +10:00
|
|
|
return cx->localeCallbacks->localeToUnicode(cx, buf, Jsvalify(vp));
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
str = JS_NewStringCopyZ(cx, buf);
|
|
|
|
|
if (!str)
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
|
|
|
|
vp->setString(str);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
|
|
|
|
|
* with msvc; '%#c' requests that a full year be used in the result string.
|
2018-09-08 18:08:48 +08:00
|
|
|
*/
|
2025-03-19 21:25:58 +10:00
|
|
|
return date_toLocaleHelper(cx, obj,
|
2018-09-08 18:08:48 +08:00
|
|
|
#if defined(_WIN32) && !defined(__MWERKS__)
|
|
|
|
|
"%#c"
|
|
|
|
|
#else
|
|
|
|
|
"%c"
|
|
|
|
|
#endif
|
2023-07-12 13:27:26 +10:00
|
|
|
, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toLocaleDateString(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
|
|
|
|
|
* with msvc; '%#x' requests that a full year be used in the result string.
|
2018-09-08 18:08:48 +08:00
|
|
|
*/
|
2025-03-19 21:25:58 +10:00
|
|
|
return date_toLocaleHelper(cx, obj,
|
2018-09-08 18:08:48 +08:00
|
|
|
#if defined(_WIN32) && !defined(__MWERKS__)
|
|
|
|
|
"%#x"
|
|
|
|
|
#else
|
|
|
|
|
"%x"
|
|
|
|
|
#endif
|
2023-07-12 13:27:26 +10:00
|
|
|
, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toLocaleTimeString(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return date_toLocaleHelper(cx, obj, "%X", vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toLocaleFormat(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
if (argc == 0)
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_toLocaleString(cx, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
JSString *fmt = js_ValueToString(cx, vp[2]);
|
2018-09-08 18:08:48 +08:00
|
|
|
if (!fmt)
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
|
|
|
|
vp[2].setString(fmt);
|
|
|
|
|
JSAutoByteString fmtbytes(cx, fmt);
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!fmtbytes)
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
return date_toLocaleHelper(cx, obj, fmtbytes.ptr(), vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toTimeString(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble utctime;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &utctime))
|
|
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_format(cx, utctime, FORMATSPEC_TIME, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toDateString(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble utctime;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &utctime))
|
|
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_format(cx, utctime, FORMATSPEC_DATE, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if JS_HAS_TOSOURCE
|
|
|
|
|
#include <string.h>
|
2025-03-19 21:25:58 +10:00
|
|
|
#include "jsnum.h"
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toSource(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble utctime;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &utctime))
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
ToCStringBuf cbuf;
|
|
|
|
|
char *numStr = NumberToCString(cx, &cbuf, utctime);
|
2018-09-08 18:08:48 +08:00
|
|
|
if (!numStr) {
|
|
|
|
|
JS_ReportOutOfMemory(cx);
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
char *bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr);
|
2018-09-08 18:08:48 +08:00
|
|
|
if (!bytes) {
|
|
|
|
|
JS_ReportOutOfMemory(cx);
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
JSString *str = JS_NewStringCopyZ(cx, bytes);
|
|
|
|
|
js_free(bytes);
|
|
|
|
|
if (!str)
|
|
|
|
|
return false;
|
|
|
|
|
vp->setString(str);
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_toString(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble utctime;
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!GetThisUTCTime(cx, vp, &utctime))
|
|
|
|
|
return false;
|
2023-07-12 13:27:26 +10:00
|
|
|
|
|
|
|
|
return date_format(cx, utctime, FORMATSPEC_FULL, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
date_valueOf(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
/*
|
|
|
|
|
* It is an error to call date_valueOf on a non-date object, but we don't
|
2018-09-08 18:08:48 +08:00
|
|
|
* need to check for that explicitly here because every path calls
|
2023-07-12 13:27:26 +10:00
|
|
|
* GetUTCTime, which does the check.
|
2018-09-08 18:08:48 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* If called directly with no arguments, convert to a time number. */
|
|
|
|
|
if (argc == 0)
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_getTime(cx, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
/* Verify this before extracting a string from the first argument. */
|
|
|
|
|
JSObject *obj = ToObject(cx, &vp[1]);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
2018-09-08 18:08:48 +08:00
|
|
|
/* Convert to number only if the hint was given, otherwise favor string. */
|
2025-03-19 21:25:58 +10:00
|
|
|
JSString *str = js_ValueToString(cx, vp[2]);
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!str)
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
|
|
|
|
JSLinearString *linear_str = str->ensureLinear(cx);
|
|
|
|
|
if (!linear_str)
|
|
|
|
|
return false;
|
|
|
|
|
JSAtom *number_str = cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER];
|
|
|
|
|
if (EqualStrings(linear_str, number_str))
|
2023-07-12 13:27:26 +10:00
|
|
|
return date_getTime(cx, argc, vp);
|
|
|
|
|
return date_toString(cx, argc, vp);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
// Don't really need an argument here, but we don't support arg-less builtins
|
|
|
|
|
JS_DEFINE_TRCINFO_1(date_now,
|
2025-03-19 21:25:58 +10:00
|
|
|
(1, (static, DOUBLE, date_now_tn, CONTEXT, 0, nanojit::ACCSET_STORE_ANY)))
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
static JSFunctionSpec date_static_methods[] = {
|
2025-02-03 12:35:24 +10:00
|
|
|
JS_FN("UTC", date_UTC, MAXARGS,0),
|
|
|
|
|
JS_FN("parse", date_parse, 1,0),
|
2025-02-05 12:40:54 +10:00
|
|
|
JS_TN("now", date_now, 0,0, &date_now_trcinfo),
|
2023-07-12 13:27:26 +10:00
|
|
|
JS_FS_END
|
2018-09-08 18:08:48 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static JSFunctionSpec date_methods[] = {
|
2025-02-03 12:35:24 +10:00
|
|
|
JS_FN("getTime", date_getTime, 0,0),
|
|
|
|
|
JS_FN("getTimezoneOffset", date_getTimezoneOffset, 0,0),
|
|
|
|
|
JS_FN("getYear", date_getYear, 0,0),
|
|
|
|
|
JS_FN("getFullYear", date_getFullYear, 0,0),
|
|
|
|
|
JS_FN("getUTCFullYear", date_getUTCFullYear, 0,0),
|
|
|
|
|
JS_FN("getMonth", date_getMonth, 0,0),
|
|
|
|
|
JS_FN("getUTCMonth", date_getUTCMonth, 0,0),
|
|
|
|
|
JS_FN("getDate", date_getDate, 0,0),
|
|
|
|
|
JS_FN("getUTCDate", date_getUTCDate, 0,0),
|
|
|
|
|
JS_FN("getDay", date_getDay, 0,0),
|
|
|
|
|
JS_FN("getUTCDay", date_getUTCDay, 0,0),
|
|
|
|
|
JS_FN("getHours", date_getHours, 0,0),
|
|
|
|
|
JS_FN("getUTCHours", date_getUTCHours, 0,0),
|
|
|
|
|
JS_FN("getMinutes", date_getMinutes, 0,0),
|
|
|
|
|
JS_FN("getUTCMinutes", date_getUTCMinutes, 0,0),
|
|
|
|
|
JS_FN("getSeconds", date_getUTCSeconds, 0,0),
|
|
|
|
|
JS_FN("getUTCSeconds", date_getUTCSeconds, 0,0),
|
|
|
|
|
JS_FN("getMilliseconds", date_getUTCMilliseconds, 0,0),
|
|
|
|
|
JS_FN("getUTCMilliseconds", date_getUTCMilliseconds, 0,0),
|
|
|
|
|
JS_FN("setTime", date_setTime, 1,0),
|
|
|
|
|
JS_FN("setYear", date_setYear, 1,0),
|
|
|
|
|
JS_FN("setFullYear", date_setFullYear, 3,0),
|
|
|
|
|
JS_FN("setUTCFullYear", date_setUTCFullYear, 3,0),
|
|
|
|
|
JS_FN("setMonth", date_setMonth, 2,0),
|
|
|
|
|
JS_FN("setUTCMonth", date_setUTCMonth, 2,0),
|
|
|
|
|
JS_FN("setDate", date_setDate, 1,0),
|
|
|
|
|
JS_FN("setUTCDate", date_setUTCDate, 1,0),
|
|
|
|
|
JS_FN("setHours", date_setHours, 4,0),
|
|
|
|
|
JS_FN("setUTCHours", date_setUTCHours, 4,0),
|
|
|
|
|
JS_FN("setMinutes", date_setMinutes, 3,0),
|
|
|
|
|
JS_FN("setUTCMinutes", date_setUTCMinutes, 3,0),
|
|
|
|
|
JS_FN("setSeconds", date_setSeconds, 2,0),
|
|
|
|
|
JS_FN("setUTCSeconds", date_setUTCSeconds, 2,0),
|
|
|
|
|
JS_FN("setMilliseconds", date_setMilliseconds, 1,0),
|
|
|
|
|
JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0),
|
|
|
|
|
JS_FN("toUTCString", date_toGMTString, 0,0),
|
|
|
|
|
JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0),
|
|
|
|
|
JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0),
|
|
|
|
|
JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0),
|
|
|
|
|
JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0),
|
|
|
|
|
JS_FN("toDateString", date_toDateString, 0,0),
|
|
|
|
|
JS_FN("toTimeString", date_toTimeString, 0,0),
|
2025-02-05 12:40:54 +10:00
|
|
|
JS_FN("toISOString", date_toISOString, 0,0),
|
2025-03-19 21:25:58 +10:00
|
|
|
JS_FN(js_toJSON_str, date_toJSON, 1,0),
|
2018-09-08 18:08:48 +08:00
|
|
|
#if JS_HAS_TOSOURCE
|
2025-02-03 12:35:24 +10:00
|
|
|
JS_FN(js_toSource_str, date_toSource, 0,0),
|
2018-09-08 18:08:48 +08:00
|
|
|
#endif
|
2025-02-03 12:35:24 +10:00
|
|
|
JS_FN(js_toString_str, date_toString, 0,0),
|
|
|
|
|
JS_FN(js_valueOf_str, date_valueOf, 0,0),
|
2023-07-12 13:27:26 +10:00
|
|
|
JS_FS_END
|
2018-09-08 18:08:48 +08:00
|
|
|
};
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
JSBool
|
2025-03-19 21:25:58 +10:00
|
|
|
js_Date(JSContext *cx, uintN argc, Value *vp)
|
2018-09-08 18:08:48 +08:00
|
|
|
{
|
|
|
|
|
/* Date called as function. */
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!IsConstructing(vp))
|
|
|
|
|
return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, vp);
|
|
|
|
|
|
|
|
|
|
Value *argv = vp + 2;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* Date called as constructor. */
|
2025-02-05 12:40:54 +10:00
|
|
|
jsdouble d;
|
2018-09-08 18:08:48 +08:00
|
|
|
if (argc == 0) {
|
2025-02-05 12:40:54 +10:00
|
|
|
d = NowAsMillis();
|
2018-09-08 18:08:48 +08:00
|
|
|
} else if (argc == 1) {
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!argv[0].isString()) {
|
2018-09-08 18:08:48 +08:00
|
|
|
/* the argument is a millisecond number */
|
2025-02-05 12:40:54 +10:00
|
|
|
if (!ValueToNumber(cx, argv[0], &d))
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
2025-02-05 12:40:54 +10:00
|
|
|
d = TIMECLIP(d);
|
2018-09-08 18:08:48 +08:00
|
|
|
} else {
|
|
|
|
|
/* the argument is a string; parse it. */
|
2025-02-05 12:40:54 +10:00
|
|
|
JSString *str = js_ValueToString(cx, argv[0]);
|
2018-09-08 18:08:48 +08:00
|
|
|
if (!str)
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
|
|
|
|
argv[0].setString(str);
|
|
|
|
|
JSLinearString *linearStr = str->ensureLinear(cx);
|
|
|
|
|
if (!linearStr)
|
|
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
if (!date_parseString(linearStr, &d, cx))
|
2025-02-05 12:40:54 +10:00
|
|
|
d = js_NaN;
|
|
|
|
|
else
|
|
|
|
|
d = TIMECLIP(d);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
jsdouble msec_time;
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!date_msecFromArgs(cx, argc, argv, &msec_time))
|
2025-03-19 21:25:58 +10:00
|
|
|
return false;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (JSDOUBLE_IS_FINITE(msec_time)) {
|
2025-02-05 12:40:54 +10:00
|
|
|
msec_time = UTC(msec_time, cx);
|
2023-07-12 13:27:26 +10:00
|
|
|
msec_time = TIMECLIP(msec_time);
|
|
|
|
|
}
|
2025-02-05 12:40:54 +10:00
|
|
|
d = msec_time;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
2025-03-19 21:25:58 +10:00
|
|
|
|
|
|
|
|
JSObject *obj = js_NewDateObjectMsec(cx, d);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
vp->setObject(*obj);
|
|
|
|
|
|
|
|
|
|
return true;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSObject *
|
|
|
|
|
js_InitDateClass(JSContext *cx, JSObject *obj)
|
|
|
|
|
{
|
|
|
|
|
/* set static LocalTZA */
|
|
|
|
|
LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *proto = js_InitClass(cx, obj, NULL, &js_DateClass, js_Date, MAXARGS,
|
|
|
|
|
NULL, date_methods, NULL, date_static_methods);
|
2018-09-08 18:08:48 +08:00
|
|
|
if (!proto)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
AutoObjectRooter tvr(cx, proto);
|
|
|
|
|
|
2025-02-05 12:40:54 +10:00
|
|
|
SetDateToNaN(cx, proto);
|
|
|
|
|
|
2025-03-19 21:25:58 +10:00
|
|
|
/*
|
|
|
|
|
* ES5 B.2.6:
|
|
|
|
|
* The Function object that is the initial value of
|
|
|
|
|
* Date.prototype.toGMTString is the same Function
|
|
|
|
|
* object that is the initial value of
|
|
|
|
|
* Date.prototype.toUTCString.
|
|
|
|
|
*/
|
|
|
|
|
AutoValueRooter toUTCStringFun(cx);
|
|
|
|
|
jsid toUTCStringId = ATOM_TO_JSID(cx->runtime->atomState.toUTCStringAtom);
|
|
|
|
|
jsid toGMTStringId = ATOM_TO_JSID(cx->runtime->atomState.toGMTStringAtom);
|
|
|
|
|
if (!js_GetProperty(cx, proto, toUTCStringId, toUTCStringFun.addr()) ||
|
|
|
|
|
!js_DefineProperty(cx, proto, toGMTStringId, toUTCStringFun.addr(),
|
|
|
|
|
PropertyStub, StrictPropertyStub, 0)) {
|
2018-09-08 18:08:48 +08:00
|
|
|
return NULL;
|
2025-03-19 21:25:58 +10:00
|
|
|
}
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
return proto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(JSObject *)
|
|
|
|
|
js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
|
|
|
|
|
{
|
2025-03-19 21:25:58 +10:00
|
|
|
JSObject *obj = NewBuiltinClassInstance(cx, &js_DateClass);
|
|
|
|
|
if (!obj || !obj->ensureSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
|
|
|
|
|
return NULL;
|
|
|
|
|
if (!SetUTCTime(cx, obj, msec_time))
|
2018-09-08 18:08:48 +08:00
|
|
|
return NULL;
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(JSObject *)
|
|
|
|
|
js_NewDateObject(JSContext* cx, int year, int mon, int mday,
|
|
|
|
|
int hour, int min, int sec)
|
|
|
|
|
{
|
|
|
|
|
JSObject *obj;
|
|
|
|
|
jsdouble msec_time;
|
|
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
JS_ASSERT(mon < 12);
|
2018-09-08 18:08:48 +08:00
|
|
|
msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
|
2025-02-05 12:40:54 +10:00
|
|
|
obj = js_NewDateObjectMsec(cx, UTC(msec_time, cx));
|
2018-09-08 18:08:48 +08:00
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(JSBool)
|
|
|
|
|
js_DateIsValid(JSContext *cx, JSObject* obj)
|
|
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble utctime;
|
|
|
|
|
return GetUTCTime(cx, obj, NULL, &utctime) && !JSDOUBLE_IS_NaN(utctime);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
|
js_DateGetYear(JSContext *cx, JSObject* obj)
|
|
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble localtime;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
|
|
|
|
/* Preserve legacy API behavior of returning 0 for invalid dates. */
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
|
|
|
|
|
JSDOUBLE_IS_NaN(localtime)) {
|
2018-09-08 18:08:48 +08:00
|
|
|
return 0;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (int) YearFromTime(localtime);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
|
js_DateGetMonth(JSContext *cx, JSObject* obj)
|
|
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble localtime;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
|
|
|
|
|
JSDOUBLE_IS_NaN(localtime)) {
|
2018-09-08 18:08:48 +08:00
|
|
|
return 0;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (int) MonthFromTime(localtime);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
|
js_DateGetDate(JSContext *cx, JSObject* obj)
|
|
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble localtime;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
|
|
|
|
|
JSDOUBLE_IS_NaN(localtime)) {
|
2018-09-08 18:08:48 +08:00
|
|
|
return 0;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (int) DateFromTime(localtime);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
|
js_DateGetHours(JSContext *cx, JSObject* obj)
|
|
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble localtime;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
|
|
|
|
|
JSDOUBLE_IS_NaN(localtime)) {
|
2018-09-08 18:08:48 +08:00
|
|
|
return 0;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (int) HourFromTime(localtime);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
|
js_DateGetMinutes(JSContext *cx, JSObject* obj)
|
|
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble localtime;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
|
|
|
|
|
JSDOUBLE_IS_NaN(localtime)) {
|
2018-09-08 18:08:48 +08:00
|
|
|
return 0;
|
2023-07-12 13:27:26 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (int) MinFromTime(localtime);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
|
js_DateGetSeconds(JSContext *cx, JSObject* obj)
|
|
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble utctime;
|
2018-09-08 18:08:48 +08:00
|
|
|
|
2023-07-12 13:27:26 +10:00
|
|
|
if (!GetUTCTime(cx, obj, NULL, &utctime) || JSDOUBLE_IS_NaN(utctime))
|
2018-09-08 18:08:48 +08:00
|
|
|
return 0;
|
2023-07-12 13:27:26 +10:00
|
|
|
|
|
|
|
|
return (int) SecFromTime(utctime);
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(jsdouble)
|
|
|
|
|
js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
|
|
|
|
|
{
|
2023-07-12 13:27:26 +10:00
|
|
|
jsdouble utctime;
|
|
|
|
|
if (!GetUTCTime(cx, obj, NULL, &utctime))
|
2018-09-08 18:08:48 +08:00
|
|
|
return 0;
|
2023-07-12 13:27:26 +10:00
|
|
|
return utctime;
|
2018-09-08 18:08:48 +08:00
|
|
|
}
|
2025-02-05 12:40:54 +10:00
|
|
|
|
|
|
|
|
#ifdef JS_THREADSAFE
|
|
|
|
|
#include "prinrval.h"
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(uint32)
|
|
|
|
|
js_IntervalNow()
|
|
|
|
|
{
|
|
|
|
|
return uint32(PR_IntervalToMilliseconds(PR_IntervalNow()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else /* !JS_THREADSAFE */
|
|
|
|
|
|
|
|
|
|
JS_FRIEND_API(uint32)
|
|
|
|
|
js_IntervalNow()
|
|
|
|
|
{
|
|
|
|
|
return uint32(PRMJ_Now() / PRMJ_USEC_PER_MSEC);
|
|
|
|
|
}
|
|
|
|
|
#endif
|