http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date.c
----------------------------------------------------------------------
diff --git 
a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date.c
 
b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date.c
new file mode 100644
index 0000000..1d5c7b7
--- /dev/null
+++ 
b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date.c
@@ -0,0 +1,1728 @@
+/*
+ *  Date built-ins
+ *
+ *  Unlike most built-ins, Date has some platform dependencies for getting
+ *  UTC time, converting between UTC and local time, and parsing and
+ *  formatting time values.  These are all abstracted behind DUK_USE_xxx
+ *  config options.  There are built-in platform specific providers for
+ *  POSIX and Windows, but external providers can also be used.
+ *
+ *  See doc/datetime.rst.
+ *
+ */
+
+#include "duk_internal.h"
+
+/*
+ *  Forward declarations
+ */
+
+DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context 
*ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset);
+DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_context *ctx, 
duk_small_uint_t flags);
+DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t 
idx_val);
+DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, 
duk_double_t *dparts, duk_small_uint_t flags);
+
+/*
+ *  Other file level defines
+ */
+
+/* Debug macro to print all parts and dparts (used manually because of debug 
level). */
+#define  DUK__DPRINT_PARTS_AND_DPARTS(parts,dparts)  do { \
+               DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld, 
dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
+                                (long) (parts)[0], (long) (parts)[1], \
+                                (long) (parts)[2], (long) (parts)[3], \
+                                (long) (parts)[4], (long) (parts)[5], \
+                                (long) (parts)[6], (long) (parts)[7], \
+                                (double) (dparts)[0], (double) (dparts)[1], \
+                                (double) (dparts)[2], (double) (dparts)[3], \
+                                (double) (dparts)[4], (double) (dparts)[5], \
+                                (double) (dparts)[6], (double) (dparts)[7])); \
+       } while (0)
+#define  DUK__DPRINT_PARTS(parts)  do { \
+               DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld", \
+                                (long) (parts)[0], (long) (parts)[1], \
+                                (long) (parts)[2], (long) (parts)[3], \
+                                (long) (parts)[4], (long) (parts)[5], \
+                                (long) (parts)[6], (long) (parts)[7])); \
+       } while (0)
+#define  DUK__DPRINT_DPARTS(dparts)  do { \
+               DUK_D(DUK_DPRINT("dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
+                                (double) (dparts)[0], (double) (dparts)[1], \
+                                (double) (dparts)[2], (double) (dparts)[3], \
+                                (double) (dparts)[4], (double) (dparts)[5], \
+                                (double) (dparts)[6], (double) (dparts)[7])); \
+       } while (0)
+
+/* Equivalent year for DST calculations outside [1970,2038[ range, see
+ * E5 Section 15.9.1.8.  Equivalent year has the same leap-year-ness and
+ * starts with the same weekday on Jan 1.
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
+ */
+#define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970))
+DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
+#if 1
+       /* This is based on V8 EquivalentYear() algorithm (see 
src/genequivyear.py):
+        * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146
+        */
+
+       /* non-leap year: sunday, monday, ... */
+       DUK__YEAR(2023), DUK__YEAR(2035), DUK__YEAR(2019), DUK__YEAR(2031),
+       DUK__YEAR(2015), DUK__YEAR(2027), DUK__YEAR(2011),
+
+       /* leap year: sunday, monday, ... */
+       DUK__YEAR(2012), DUK__YEAR(2024), DUK__YEAR(2008), DUK__YEAR(2020),
+       DUK__YEAR(2032), DUK__YEAR(2016), DUK__YEAR(2028)
+#endif
+
+#if 0
+       /* This is based on Rhino EquivalentYear() algorithm:
+        * 
https://github.com/mozilla/rhino/blob/f99cc11d616f0cdda2c42bde72b3484df6182947/src/org/mozilla/javascript/NativeDate.java
+        */
+
+       /* non-leap year: sunday, monday, ... */
+       DUK__YEAR(1978), DUK__YEAR(1973), DUK__YEAR(1985), DUK__YEAR(1986),
+       DUK__YEAR(1981), DUK__YEAR(1971), DUK__YEAR(1977),
+
+       /* leap year: sunday, monday, ... */
+       DUK__YEAR(1984), DUK__YEAR(1996), DUK__YEAR(1980), DUK__YEAR(1992),
+       DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972)
+#endif
+};
+#undef DUK__YEAR
+
+/*
+ *  ISO 8601 subset parser.
+ */
+
+/* Parser part count. */
+#define DUK__NUM_ISO8601_PARSER_PARTS  9
+
+/* Parser part indices. */
+#define DUK__PI_YEAR         0
+#define DUK__PI_MONTH        1
+#define DUK__PI_DAY          2
+#define DUK__PI_HOUR         3
+#define DUK__PI_MINUTE       4
+#define DUK__PI_SECOND       5
+#define DUK__PI_MILLISECOND  6
+#define DUK__PI_TZHOUR       7
+#define DUK__PI_TZMINUTE     8
+
+/* Parser part masks. */
+#define DUK__PM_YEAR         (1 << DUK__PI_YEAR)
+#define DUK__PM_MONTH        (1 << DUK__PI_MONTH)
+#define DUK__PM_DAY          (1 << DUK__PI_DAY)
+#define DUK__PM_HOUR         (1 << DUK__PI_HOUR)
+#define DUK__PM_MINUTE       (1 << DUK__PI_MINUTE)
+#define DUK__PM_SECOND       (1 << DUK__PI_SECOND)
+#define DUK__PM_MILLISECOND  (1 << DUK__PI_MILLISECOND)
+#define DUK__PM_TZHOUR       (1 << DUK__PI_TZHOUR)
+#define DUK__PM_TZMINUTE     (1 << DUK__PI_TZMINUTE)
+
+/* Parser separator indices. */
+#define DUK__SI_PLUS         0
+#define DUK__SI_MINUS        1
+#define DUK__SI_T            2
+#define DUK__SI_SPACE        3
+#define DUK__SI_COLON        4
+#define DUK__SI_PERIOD       5
+#define DUK__SI_Z            6
+#define DUK__SI_NUL          7
+
+/* Parser separator masks. */
+#define DUK__SM_PLUS         (1 << DUK__SI_PLUS)
+#define DUK__SM_MINUS        (1 << DUK__SI_MINUS)
+#define DUK__SM_T            (1 << DUK__SI_T)
+#define DUK__SM_SPACE        (1 << DUK__SI_SPACE)
+#define DUK__SM_COLON        (1 << DUK__SI_COLON)
+#define DUK__SM_PERIOD       (1 << DUK__SI_PERIOD)
+#define DUK__SM_Z            (1 << DUK__SI_Z)
+#define DUK__SM_NUL          (1 << DUK__SI_NUL)
+
+/* Rule control flags. */
+#define DUK__CF_NEG          (1 << 0)  /* continue matching, set neg_tzoffset 
flag */
+#define DUK__CF_ACCEPT       (1 << 1)  /* accept string */
+#define DUK__CF_ACCEPT_NUL   (1 << 2)  /* accept string if next char is NUL 
(otherwise reject) */
+
+#define DUK__PACK_RULE(partmask,sepmask,nextpart,flags)  \
+       ((duk_uint32_t) (partmask) + \
+        (((duk_uint32_t) (sepmask)) << 9) + \
+        (((duk_uint32_t) (nextpart)) << 17) + \
+        (((duk_uint32_t) (flags)) << 21))
+
+#define DUK__UNPACK_RULE(rule,var_nextidx,var_flags)  do { \
+               (var_nextidx) = (duk_small_uint_t) (((rule) >> 17) & 0x0f); \
+               (var_flags) = (duk_small_uint_t) ((rule) >> 21); \
+       } while (0)
+
+#define DUK__RULE_MASK_PART_SEP  0x1ffffUL
+
+/* Matching separator index is used in the control table */
+DUK_LOCAL const duk_uint8_t duk__parse_iso8601_seps[] = {
+       DUK_ASC_PLUS /*0*/, DUK_ASC_MINUS /*1*/, DUK_ASC_UC_T /*2*/, 
DUK_ASC_SPACE /*3*/,
+       DUK_ASC_COLON /*4*/, DUK_ASC_PERIOD /*5*/, DUK_ASC_UC_Z /*6*/, 
DUK_ASC_NUL /*7*/
+};
+
+/* Rule table: first matching rule is used to determine what to do next. */
+DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
+       DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0),
+       DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0),
+       DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | 
DUK__SM_SPACE, DUK__PI_HOUR, 0),
+       DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0),
+       DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0),
+       DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0),
+       DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0),
+       DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | 
DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, 
DUK__SM_PLUS, DUK__PI_TZHOUR, 0),
+       DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | 
DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, 
DUK__SM_MINUS, DUK__PI_TZHOUR, DUK__CF_NEG),
+       DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | 
DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, 
DUK__SM_Z, 0, DUK__CF_ACCEPT_NUL),
+       DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | 
DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND 
| DUK__PM_TZHOUR /*Note2*/ | DUK__PM_TZMINUTE, DUK__SM_NUL, 0, DUK__CF_ACCEPT)
+
+       /* Note1: the specification doesn't require matching a time form with
+        *        just hours ("HH"), but we accept it here, e.g. 
"2012-01-02T12Z".
+        *
+        * Note2: the specification doesn't require matching a timezone offset
+        *        with just hours ("HH"), but accept it here, e.g. 
"2012-01-02T03:04:05+02"
+        */
+};
+
+DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const 
char *str) {
+       duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
+       duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
+       duk_double_t d;
+       const duk_uint8_t *p;
+       duk_small_uint_t part_idx = 0;
+       duk_int_t accum = 0;
+       duk_small_uint_t ndigits = 0;
+       duk_bool_t neg_year = 0;
+       duk_bool_t neg_tzoffset = 0;
+       duk_uint_fast8_t ch;
+       duk_small_uint_t i;
+
+       /* During parsing, month and day are one-based; set defaults here. */
+       DUK_MEMZERO(parts, sizeof(parts));
+       DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0);  /* don't care value, year 
is mandatory */
+       parts[DUK_DATE_IDX_MONTH] = 1;
+       parts[DUK_DATE_IDX_DAY] = 1;
+
+       /* Special handling for year sign. */
+       p = (const duk_uint8_t *) str;
+       ch = p[0];
+       if (ch == DUK_ASC_PLUS) {
+               p++;
+       } else if (ch == DUK_ASC_MINUS) {
+               neg_year = 1;
+               p++;
+       }
+
+       for (;;) {
+               ch = *p++;
+               DUK_DDD(DUK_DDDPRINT("parsing, part_idx=%ld, char=%ld ('%c')",
+                                    (long) part_idx, (long) ch,
+                                    (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : 
DUK_ASC_QUESTION)));
+
+               if (ch >= DUK_ASC_0 && ch <= DUK_ASC_9) {
+                       if (ndigits >= 9) {
+                               DUK_DDD(DUK_DDDPRINT("too many digits -> 
reject"));
+                               goto reject;
+                       }
+                       if (part_idx == DUK__PI_MILLISECOND /*msec*/ && ndigits 
>= 3) {
+                               /* ignore millisecond fractions after 3 */
+                       } else {
+                               accum = accum * 10 + ((duk_int_t) ch) - 
((duk_int_t) DUK_ASC_0) + 0x00;
+                               ndigits++;
+                       }
+               } else {
+                       duk_uint_fast32_t match_val;
+                       duk_small_int_t sep_idx;
+
+                       if (ndigits <= 0) {
+                               goto reject;
+                       }
+                       if (part_idx == DUK__PI_MILLISECOND) {
+                               /* complete the millisecond field */
+                               while (ndigits < 3) {
+                                       accum *= 10;
+                                       ndigits++;
+                               }
+                       }
+                       parts[part_idx] = accum;
+                       DUK_DDD(DUK_DDDPRINT("wrote part %ld -> value %ld", 
(long) part_idx, (long) accum));
+
+                       accum = 0;
+                       ndigits = 0;
+
+                       for (i = 0; i < (duk_small_uint_t) 
(sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t)); i++) {
+                               if (duk__parse_iso8601_seps[i] == ch) {
+                                       break;
+                               }
+                       }
+                       if (i == (duk_small_uint_t) 
(sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t))) {
+                               DUK_DDD(DUK_DDDPRINT("separator character 
doesn't match -> reject"));
+                               goto reject;
+                       }
+
+                       sep_idx = i;
+                       match_val = (1UL << part_idx) + (1UL << (sep_idx + 9)); 
 /* match against rule part/sep bits */
+
+                       for (i = 0; i < (duk_small_uint_t) 
(sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t)); i++) {
+                               duk_uint_fast32_t rule = 
duk__parse_iso8601_control[i];
+                               duk_small_uint_t nextpart;
+                               duk_small_uint_t cflags;
+
+                               DUK_DDD(DUK_DDDPRINT("part_idx=%ld, 
sep_idx=%ld, match_val=0x%08lx, considering rule=0x%08lx",
+                                                    (long) part_idx, (long) 
sep_idx,
+                                                    (unsigned long) match_val, 
(unsigned long) rule));
+
+                               if ((rule & match_val) != match_val) {
+                                       continue;
+                               }
+
+                               DUK__UNPACK_RULE(rule, nextpart, cflags);
+
+                               DUK_DDD(DUK_DDDPRINT("rule match -> 
part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, "
+                                                    "rule=0x%08lx -> 
nextpart=%ld, cflags=0x%02lx",
+                                                    (long) part_idx, (long) 
sep_idx,
+                                                    (unsigned long) match_val, 
(unsigned long) rule,
+                                                    (long) nextpart, (unsigned 
long) cflags));
+
+                               if (cflags & DUK__CF_NEG) {
+                                       neg_tzoffset = 1;
+                               }
+
+                               if (cflags & DUK__CF_ACCEPT) {
+                                       goto accept;
+                               }
+
+                               if (cflags & DUK__CF_ACCEPT_NUL) {
+                                       DUK_ASSERT(*(p - 1) != (char) 0);
+                                       if (*p == DUK_ASC_NUL) {
+                                               goto accept;
+                                       }
+                                       goto reject;
+                               }
+
+                               part_idx = nextpart;
+                               break;
+                       }  /* rule match */
+
+                       if (i == (duk_small_uint_t) 
(sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t))) {
+                               DUK_DDD(DUK_DDDPRINT("no rule matches -> 
reject"));
+                               goto reject;
+                       }
+
+                       if (ch == 0) {
+                               /* This shouldn't be necessary, but check just 
in case
+                                * to avoid any chance of overruns.
+                                */
+                               DUK_DDD(DUK_DDDPRINT("NUL after rule matching 
(should not happen) -> reject"));
+                               goto reject;
+                       }
+               }  /* if-digit-else-ctrl */
+       }  /* char loop */
+
+       /* We should never exit the loop above. */
+       DUK_UNREACHABLE();
+
+ reject:
+       DUK_DDD(DUK_DDDPRINT("reject"));
+       return 0;
+
+ accept:
+       DUK_DDD(DUK_DDDPRINT("accept"));
+
+       /* Apply timezone offset to get the main parts in UTC */
+       if (neg_year) {
+               parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR];
+       }
+       if (neg_tzoffset) {
+               parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR];
+               parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE];
+       } else {
+               parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR];
+               parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE];
+       }
+       parts[DUK__PI_MONTH] -= 1;  /* zero-based month */
+       parts[DUK__PI_DAY] -= 1;  /* zero-based day */
+
+       /* Use double parts, they tolerate unnormalized time.
+        *
+        * Note: DUK_DATE_IDX_WEEKDAY is initialized with a bogus value 
(DUK__PI_TZHOUR)
+        * on purpose.  It won't be actually used by 
duk_bi_date_get_timeval_from_dparts(),
+        * but will make the value initialized just in case, and avoid any
+        * potential for Valgrind issues.
+        */
+       for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
+               DUK_DDD(DUK_DDDPRINT("part[%ld] = %ld", (long) i, (long) 
parts[i]));
+               dparts[i] = parts[i];
+       }
+
+       d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
+       duk_push_number(ctx, d);
+       return 1;
+}
+
+/*
+ *  Date/time parsing helper.
+ *
+ *  Parse a datetime string into a time value.  We must first try to parse
+ *  the input according to the standard format in E5.1 Section 15.9.1.15.
+ *  If that fails, we can try to parse using custom parsing, which can
+ *  either be platform neutral (custom code) or platform specific (using
+ *  existing platform API calls).
+ *
+ *  Note in particular that we must parse whatever toString(), toUTCString(),
+ *  and toISOString() can produce; see E5.1 Section 15.9.4.2.
+ *
+ *  Returns 1 to allow tail calling.
+ *
+ *  There is much room for improvement here with respect to supporting
+ *  alternative datetime formats.  For instance, V8 parses '2012-01-01' as
+ *  UTC and '2012/01/01' as local time.
+ */
+
+DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
+       /* XXX: there is a small risk here: because the ISO 8601 parser is
+        * very loose, it may end up parsing some datetime values which
+        * would be better parsed with a platform specific parser.
+        */
+
+       DUK_ASSERT(str != NULL);
+       DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) 
str));
+
+       if (duk__parse_string_iso8601_subset(ctx, str) != 0) {
+               return 1;
+       }
+
+#if defined(DUK_USE_DATE_PARSE_STRING)
+       /* Contract, either:
+        * - Push value on stack and return 1
+        * - Don't push anything on stack and return 0
+        */
+
+       if (DUK_USE_DATE_PARSE_STRING(ctx, str) != 0) {
+               return 1;
+       }
+#else
+       /* No platform-specific parsing, this is not an error. */
+#endif
+
+       duk_push_nan(ctx);
+       return 1;
+}
+
+/*
+ *  Calendar helpers
+ *
+ *  Some helpers are used for getters and can operate on normalized values
+ *  which can be represented with 32-bit signed integers.  Other helpers are
+ *  needed by setters and operate on un-normalized double values, must watch
+ *  out for non-finite numbers etc.
+ */
+
+DUK_LOCAL duk_uint8_t duk__days_in_month[12] = {
+       (duk_uint8_t) 31, (duk_uint8_t) 28, (duk_uint8_t) 31, (duk_uint8_t) 30,
+       (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 31,
+       (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31
+};
+
+/* Maximum iteration count for computing UTC-to-local time offset when
+ * creating an Ecmascript time value from local parts.
+ */
+#define DUK__LOCAL_TZOFFSET_MAXITER   4
+
+/* Because 'day since epoch' can be negative and is used to compute weekday
+ * using a modulo operation, add this multiple of 7 to avoid negative values
+ * when year is below 1970 epoch.  Ecmascript time values are restricted to
+ * +/- 100 million days from epoch, so this adder fits nicely into 32 bits.
+ * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin.
+ */
+#define DUK__WEEKDAY_MOD_ADDER  (20000000 * 7)  /* 0x08583b00 */
+
+DUK_INTERNAL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year) {
+       if ((year % 4) != 0) {
+               return 0;
+       }
+       if ((year % 100) != 0) {
+               return 1;
+       }
+       if ((year % 400) != 0) {
+               return 0;
+       }
+       return 1;
+}
+
+DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x) {
+       return (x >= -DUK_DATE_MSEC_100M_DAYS && x <= DUK_DATE_MSEC_100M_DAYS);
+}
+
+DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x) {
+       return (x >= -DUK_DATE_MSEC_100M_DAYS_LEEWAY && x <= 
DUK_DATE_MSEC_100M_DAYS_LEEWAY);
+}
+
+DUK_INTERNAL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t x) {
+       return (x >= DUK_DATE_MIN_ECMA_YEAR && x <= DUK_DATE_MAX_ECMA_YEAR);
+}
+
+DUK_LOCAL duk_double_t duk__timeclip(duk_double_t x) {
+       if (!DUK_ISFINITE(x)) {
+               return DUK_DOUBLE_NAN;
+       }
+
+       if (!duk_bi_date_timeval_in_valid_range(x)) {
+               return DUK_DOUBLE_NAN;
+       }
+
+       x = duk_js_tointeger_number(x);
+
+       /* Here we'd have the option to normalize -0 to +0. */
+       return x;
+}
+
+/* Integer division which floors also negative values correctly. */
+DUK_LOCAL duk_int_t duk__div_floor(duk_int_t a, duk_int_t b) {
+       DUK_ASSERT(b > 0);
+       if (a >= 0) {
+               return a / b;
+       } else {
+               /* e.g. a = -4, b = 5  -->  -4 - 5 + 1 / 5  -->  -8 / 5  -->  -1
+                *      a = -5, b = 5  -->  -5 - 5 + 1 / 5  -->  -9 / 5  -->  -1
+                *      a = -6, b = 5  -->  -6 - 5 + 1 / 5  -->  -10 / 5  -->  
-2
+                */
+               return (a - b + 1) / b;
+       }
+}
+
+/* Compute day number of the first day of a given year. */
+DUK_LOCAL duk_int_t duk__day_from_year(duk_int_t year) {
+       /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for 
non-negative
+        * values, but is incorrect for negative ones.
+        */
+       return 365 * (year - 1970)
+              + duk__div_floor(year - 1969, 4)
+              - duk__div_floor(year - 1901, 100)
+              + duk__div_floor(year - 1601, 400);
+}
+
+/* Given a day number, determine year and day-within-year. */
+DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t 
*out_day_within_year) {
+       duk_int_t year;
+       duk_int_t diff_days;
+
+       /* estimate year upwards (towards positive infinity), then back down;
+        * two iterations should be enough
+        */
+
+       if (day >= 0) {
+               year = 1970 + day / 365;
+       } else {
+               year = 1970 + day / 366;
+       }
+
+       for (;;) {
+               diff_days = duk__day_from_year(year) - day;
+               DUK_DDD(DUK_DDDPRINT("year=%ld day=%ld, diff_days=%ld", (long) 
year, (long) day, (long) diff_days));
+               if (diff_days <= 0) {
+                       DUK_ASSERT(-diff_days < 366);  /* fits into 
duk_small_int_t */
+                       *out_day_within_year = -diff_days;
+                       DUK_DDD(DUK_DDDPRINT("--> year=%ld, 
day-within-year=%ld",
+                                            (long) year, (long) 
*out_day_within_year));
+                       DUK_ASSERT(*out_day_within_year >= 0);
+                       DUK_ASSERT(*out_day_within_year < 
(duk_bi_date_is_leap_year(year) ? 366 : 365));
+                       return year;
+               }
+
+               /* Note: this is very tricky; we must never 'overshoot' the
+                * correction downwards.
+                */
+               year -= 1 + (diff_days - 1) / 366;  /* conservative */
+       }
+}
+
+/* Given a (year, month, day-within-month) triple, compute day number.
+ * The input triple is un-normalized and may contain non-finite values.
+ */
+DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, 
duk_double_t day) {
+       duk_int_t day_num;
+       duk_bool_t is_leap;
+       duk_small_int_t i, n;
+
+       /* Assume that year, month, day are all coerced to whole numbers.
+        * They may also be NaN or infinity, in which case this function
+        * must return NaN or infinity to ensure time value becomes NaN.
+        * If 'day' is NaN, the final return will end up returning a NaN,
+        * so it doesn't need to be checked here.
+        */
+
+       if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) {
+               return DUK_DOUBLE_NAN;
+       }
+
+       year += DUK_FLOOR(month / 12.0);
+
+       month = DUK_FMOD(month, 12.0);
+       if (month < 0.0) {
+               /* handle negative values */
+               month += 12.0;
+       }
+
+       /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but
+        * does not normalize the day-of-month (nor check whether or not
+        * it is finite) because it's not necessary for finding the day
+        * number which matches the (year,month) pair.
+        *
+        * We assume that duk__day_from_year() is exact here.
+        *
+        * Without an explicit infinity / NaN check in the beginning,
+        * day_num would be a bogus integer here.
+        *
+        * It's possible for 'year' to be out of integer range here.
+        * If so, we need to return NaN without integer overflow.
+        * This fixes test-bug-setyear-overflow.js.
+        */
+
+       if (!duk_bi_date_year_in_valid_range(year)) {
+               DUK_DD(DUK_DDPRINT("year not in ecmascript valid range, avoid 
integer overflow: %lf", (double) year));
+               return DUK_DOUBLE_NAN;
+       }
+       day_num = duk__day_from_year((duk_int_t) year);
+       is_leap = duk_bi_date_is_leap_year((duk_int_t) year);
+
+       n = (duk_small_int_t) month;
+       for (i = 0; i < n; i++) {
+               day_num += duk__days_in_month[i];
+               if (i == 1 && is_leap) {
+                       day_num++;
+               }
+       }
+
+       /* If 'day' is NaN, returns NaN. */
+       return (duk_double_t) day_num + day;
+}
+
+/* Split time value into parts.  The time value is assumed to be an internal
+ * one, i.e. finite, no fractions.  Possible local time adjustment has already
+ * been applied when reading the time value.
+ */
+DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t 
*parts, duk_double_t *dparts, duk_small_uint_t flags) {
+       duk_double_t d1, d2;
+       duk_int_t t1, t2;
+       duk_int_t day_since_epoch;
+       duk_int_t year;  /* does not fit into 16 bits */
+       duk_small_int_t day_in_year;
+       duk_small_int_t month;
+       duk_small_int_t day;
+       duk_small_int_t dim;
+       duk_int_t jan1_since_epoch;
+       duk_small_int_t jan1_weekday;
+       duk_int_t equiv_year;
+       duk_small_uint_t i;
+       duk_bool_t is_leap;
+       duk_small_int_t arridx;
+
+       DUK_ASSERT(DUK_ISFINITE(d));    /* caller checks */
+       DUK_ASSERT(DUK_FLOOR(d) == d);  /* no fractions in internal time */
+
+       /* The timevalue must be in valid Ecmascript range, but since a local
+        * time offset can be applied, we need to allow a +/- 24h leeway to
+        * the value.  In other words, although the UTC time is within the
+        * Ecmascript range, the local part values can be just outside of it.
+        */
+       DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
+       DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
+
+       /* these computations are guaranteed to be exact for the valid
+        * E5 time value range, assuming milliseconds without fractions.
+        */
+       d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
+       if (d1 < 0.0) {
+               /* deal with negative values */
+               d1 += (duk_double_t) DUK_DATE_MSEC_DAY;
+       }
+       d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY));
+       DUK_ASSERT(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1 == d);
+       /* now expected to fit into a 32-bit integer */
+       t1 = (duk_int_t) d1;
+       t2 = (duk_int_t) d2;
+       day_since_epoch = t2;
+       DUK_ASSERT((duk_double_t) t1 == d1);
+       DUK_ASSERT((duk_double_t) t2 == d2);
+
+       /* t1 = milliseconds within day (fits 32 bit)
+        * t2 = day number from epoch (fits 32 bit, may be negative)
+        */
+
+       parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000;
+       parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60;
+       parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60;
+       parts[DUK_DATE_IDX_HOUR] = t1;
+       DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && 
parts[DUK_DATE_IDX_MILLISECOND] <= 999);
+       DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && 
parts[DUK_DATE_IDX_SECOND] <= 59);
+       DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && 
parts[DUK_DATE_IDX_MINUTE] <= 59);
+       DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 
23);
+
+       DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: 
hour=%ld min=%ld sec=%ld msec=%ld",
+                            (double) d, (double) d1, (double) d2, (long) t1, 
(long) t2,
+                            (long) parts[DUK_DATE_IDX_HOUR],
+                            (long) parts[DUK_DATE_IDX_MINUTE],
+                            (long) parts[DUK_DATE_IDX_SECOND],
+                            (long) parts[DUK_DATE_IDX_MILLISECOND]));
+
+       /* This assert depends on the input parts representing time inside
+        * the Ecmascript range.
+        */
+       DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0);
+       parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7;  
/* E5.1 Section 15.9.1.6 */
+       DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && 
parts[DUK_DATE_IDX_WEEKDAY] <= 6);
+
+       year = duk__year_from_day(t2, &day_in_year);
+       day = day_in_year;
+       is_leap = duk_bi_date_is_leap_year(year);
+       for (month = 0; month < 12; month++) {
+               dim = duk__days_in_month[month];
+               if (month == 1 && is_leap) {
+                       dim++;
+               }
+               DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld",
+                                    (long) month, (long) dim, (long) day));
+               if (day < dim) {
+                       break;
+               }
+               day -= dim;
+       }
+       DUK_DDD(DUK_DDDPRINT("final month=%ld", (long) month));
+       DUK_ASSERT(month >= 0 && month <= 11);
+       DUK_ASSERT(day >= 0 && day <= 31);
+
+       /* Equivalent year mapping, used to avoid DST trouble when platform
+        * may fail to provide reasonable DST answers for dates outside the
+        * ordinary range (e.g. 1970-2038).  An equivalent year has the same
+        * leap-year-ness as the original year and begins on the same weekday
+        * (Jan 1).
+        *
+        * The year 2038 is avoided because there seem to be problems with it
+        * on some platforms.  The year 1970 is also avoided as there were
+        * practical problems with it; an equivalent year is used for it too,
+        * which breaks some DST computations for 1970 right now, see e.g.
+        * test-bi-date-tzoffset-brute-fi.js.
+        */
+       if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) {
+               DUK_ASSERT(is_leap == 0 || is_leap == 1);
+
+               jan1_since_epoch = day_since_epoch - day_in_year;  /* day 
number for Jan 1 since epoch */
+               DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0);
+               jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) 
% 7;  /* E5.1 Section 15.9.1.6 */
+               DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6);
+               arridx = jan1_weekday;
+               if (is_leap) {
+                       arridx += 7;
+               }
+               DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) 
(sizeof(duk__date_equivyear) / sizeof(duk_uint8_t)));
+
+               equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970;
+               year = equiv_year;
+               DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, 
day_in_year=%ld, day_since_epoch=%ld, "
+                                    "jan1_since_epoch=%ld, jan1_weekday=%ld -> 
equiv year %ld",
+                                    (long) year, (long) day_in_year, (long) 
day_since_epoch,
+                                    (long) jan1_since_epoch, (long) 
jan1_weekday, (long) equiv_year));
+       }
+
+       parts[DUK_DATE_IDX_YEAR] = year;
+       parts[DUK_DATE_IDX_MONTH] = month;
+       parts[DUK_DATE_IDX_DAY] = day;
+
+       if (flags & DUK_DATE_FLAG_ONEBASED) {
+               parts[DUK_DATE_IDX_MONTH]++;  /* zero-based -> one-based */
+               parts[DUK_DATE_IDX_DAY]++;    /* -""- */
+       }
+
+       if (dparts != NULL) {
+               for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
+                       dparts[i] = (duk_double_t) parts[i];
+               }
+       }
+}
+
+/* Compute time value from (double) parts.  The parts can be either UTC
+ * or local time; if local, they need to be (conceptually) converted into
+ * UTC time.  The parts may represent valid or invalid time, and may be
+ * wildly out of range (but may cancel each other and still come out in
+ * the valid Date range).
+ */
+DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t 
*dparts, duk_small_uint_t flags) {
+#if defined(DUK_USE_PARANOID_DATE_COMPUTATION)
+       /* See comments below on MakeTime why these are volatile. */
+       volatile duk_double_t tmp_time;
+       volatile duk_double_t tmp_day;
+       volatile duk_double_t d;
+#else
+       duk_double_t tmp_time;
+       duk_double_t tmp_day;
+       duk_double_t d;
+#endif
+       duk_small_uint_t i;
+       duk_int_t tzoff, tzoffprev1, tzoffprev2;
+
+       /* Expects 'this' at top of stack on entry. */
+
+       /* Coerce all finite parts with ToInteger().  ToInteger() must not
+        * be called for NaN/Infinity because it will convert e.g. NaN to
+        * zero.  If ToInteger() has already been called, this has no side
+        * effects and is idempotent.
+        *
+        * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind
+        * issues if the value is uninitialized.
+        */
+       for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) {
+               /* SCANBUILD: scan-build complains here about assigned value
+                * being garbage or undefined.  This is correct but operating
+                * on undefined values has no ill effect and is ignored by the
+                * caller in the case where this happens.
+                */
+               d = dparts[i];
+               if (DUK_ISFINITE(d)) {
+                       dparts[i] = duk_js_tointeger_number(d);
+               }
+       }
+
+       /* Use explicit steps in computation to try to ensure that
+        * computation happens with intermediate results coerced to
+        * double values (instead of using something more accurate).
+        * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
+        * rules (= Ecmascript '+' and '*' operators).
+        *
+        * Without 'volatile' even this approach fails on some platform
+        * and compiler combinations.  For instance, gcc 4.8.1 on Ubuntu
+        * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js
+        * would fail because of some optimizations when computing tmp_time
+        * (MakeTime below).  Adding 'volatile' to tmp_time solved this
+        * particular problem (annoyingly, also adding debug prints or
+        * running the executable under valgrind hides it).
+        */
+
+       /* MakeTime */
+       tmp_time = 0.0;
+       tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) 
DUK_DATE_MSEC_HOUR);
+       tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) 
DUK_DATE_MSEC_MINUTE);
+       tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) 
DUK_DATE_MSEC_SECOND);
+       tmp_time += dparts[DUK_DATE_IDX_MILLISECOND];
+
+       /* MakeDay */
+       tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], 
dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]);
+
+       /* MakeDate */
+       d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time;
+
+       DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf",
+                            (double) tmp_time, (double) tmp_day, (double) d));
+
+       /* Optional UTC conversion. */
+       if (flags & DUK_DATE_FLAG_LOCALTIME) {
+               /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a
+                * time value computed from UTC parts.  At this point we only
+                * have 'd' which is a time value computed from local parts, so
+                * it is off by the UTC-to-local time offset which we don't know
+                * yet.  The current solution for computing the UTC-to-local
+                * time offset is to iterate a few times and detect a fixed
+                * point or a two-cycle loop (or a sanity iteration limit),
+                * see test-bi-date-local-parts.js and 
test-bi-date-tzoffset-basic-fi.js.
+                *
+                * E5.1 Section 15.9.1.9:
+                * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
+                *
+                * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0.
+                */
+
+#if 0
+               /* Old solution: don't iterate, incorrect */
+               tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
+               DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld", 
(long) tzoff));
+               d -= tzoff * 1000L;
+               DUK_UNREF(tzoffprev1);
+               DUK_UNREF(tzoffprev2);
+#endif
+
+               /* Iteration solution */
+               tzoff = 0;
+               tzoffprev1 = 999999999L;  /* invalid value which never matches 
*/
+               for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) {
+                       tzoffprev2 = tzoffprev1;
+                       tzoffprev1 = tzoff;
+                       tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 
1000L);
+                       DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, 
tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld",
+                                            (int) i, (long) tzoff, (long) 
tzoffprev1, (long) tzoffprev2));
+                       if (tzoff == tzoffprev1) {
+                               DUK_DDD(DUK_DDDPRINT("tzoffset iteration 
finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
+                                                    (int) i, (long) tzoff, 
(long) tzoffprev1, (long) tzoffprev2));
+                               break;
+                       } else if (tzoff == tzoffprev2) {
+                               /* Two value cycle, see e.g. 
test-bi-date-tzoffset-basic-fi.js.
+                                * In these cases, favor a higher tzoffset to 
get a consistent
+                                * result which is independent of iteration 
count.  Not sure if
+                                * this is a generically correct solution.
+                                */
+                               DUK_DDD(DUK_DDDPRINT("tzoffset iteration 
two-value cycle, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
+                                                    (int) i, (long) tzoff, 
(long) tzoffprev1, (long) tzoffprev2));
+                               if (tzoffprev1 > tzoff) {
+                                       tzoff = tzoffprev1;
+                               }
+                               break;
+                       }
+               }
+               DUK_DDD(DUK_DDDPRINT("tzoffset iteration, tzoff=%ld", (long) 
tzoff));
+               d -= tzoff * 1000L;
+       }
+
+       /* TimeClip(), which also handles Infinity -> NaN conversion */
+       d = duk__timeclip(d);
+
+       return d;
+}
+
+/*
+ *  API oriented helpers
+ */
+
+/* Push 'this' binding, check that it is a Date object; then push the
+ * internal time value.  At the end, stack is: [ ... this timeval ].
+ * Returns the time value.  Local time adjustment is done if requested.
+ */
+DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, 
duk_small_uint_t flags, duk_int_t *out_tzoffset) {
+       duk_hthread *thr = (duk_hthread *) ctx;
+       duk_hobject *h;
+       duk_double_t d;
+       duk_int_t tzoffset = 0;
+
+       duk_push_this(ctx);
+       h = duk_get_hobject(ctx, -1);  /* XXX: getter with class check, useful 
in built-ins */
+       if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != 
DUK_HOBJECT_CLASS_DATE) {
+               DUK_ERROR_TYPE(thr, "expected Date");
+       }
+
+       duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
+       d = duk_to_number(ctx, -1);
+       duk_pop(ctx);
+
+       if (DUK_ISNAN(d)) {
+               if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
+                       d = 0.0;
+               }
+               if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) {
+                       DUK_ERROR_RANGE(thr, "Invalid Date");
+               }
+       }
+       /* if no NaN handling flag, may still be NaN here, but not Inf */
+       DUK_ASSERT(!DUK_ISINF(d));
+
+       if (flags & DUK_DATE_FLAG_LOCALTIME) {
+               /* Note: DST adjustment is determined using UTC time.
+                * If 'd' is NaN, tzoffset will be 0.
+                */
+               tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);  /* seconds */
+               d += tzoffset * 1000L;
+       }
+       if (out_tzoffset) {
+               *out_tzoffset = tzoffset;
+       }
+
+       /* [ ... this ] */
+       return d;
+}
+
+DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_context *ctx, 
duk_small_uint_t flags) {
+       return duk__push_this_get_timeval_tzoffset(ctx, flags, NULL);
+}
+
+/* Set timeval to 'this' from dparts, push the new time value onto the
+ * value stack and return 1 (caller can then tail call us).  Expects
+ * the value stack to contain 'this' on the stack top.
+ */
+DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, 
duk_double_t *dparts, duk_small_uint_t flags) {
+       duk_double_t d;
+
+       /* [ ... this ] */
+
+       d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
+       duk_push_number(ctx, d);  /* -> [ ... this timeval_new ] */
+       duk_dup_top(ctx);         /* -> [ ... this timeval_new timeval_new ] */
+       duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE);
+
+       /* stack top: new time value, return 1 to allow tail calls */
+       return 1;
+}
+
+/* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */
+DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, 
duk_small_uint_t flags, duk_uint8_t *out_buf) {
+       char yearstr[8];   /* "-123456\0" */
+       char tzstr[8];     /* "+11:22\0" */
+       char sep = (flags & DUK_DATE_FLAG_SEP_T) ? DUK_ASC_UC_T : DUK_ASC_SPACE;
+
+       DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] 
<= 12);
+       DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 
31);
+       DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= -999999 && 
parts[DUK_DATE_IDX_YEAR] <= 999999);
+
+       /* Note: %06d for positive value, %07d for negative value to include
+        * sign and 6 digits.
+        */
+       DUK_SNPRINTF(yearstr,
+                    sizeof(yearstr),
+                    (parts[DUK_DATE_IDX_YEAR] >= 0 && parts[DUK_DATE_IDX_YEAR] 
<= 9999) ? "%04ld" :
+                           ((parts[DUK_DATE_IDX_YEAR] >= 0) ? "+%06ld" : 
"%07ld"),
+                    (long) parts[DUK_DATE_IDX_YEAR]);
+       yearstr[sizeof(yearstr) - 1] = (char) 0;
+
+       if (flags & DUK_DATE_FLAG_LOCALTIME) {
+               /* tzoffset seconds are dropped; 16 bits suffice for
+                * time offset in minutes
+                */
+               if (tzoffset >= 0) {
+                       duk_small_int_t tmp = tzoffset / 60;
+                       DUK_SNPRINTF(tzstr, sizeof(tzstr), "+%02d:%02d", (int) 
(tmp / 60), (int) (tmp % 60));
+               } else {
+                       duk_small_int_t tmp = -tzoffset / 60;
+                       DUK_SNPRINTF(tzstr, sizeof(tzstr), "-%02d:%02d", (int) 
(tmp / 60), (int) (tmp % 60));
+               }
+               tzstr[sizeof(tzstr) - 1] = (char) 0;
+       } else {
+               tzstr[0] = DUK_ASC_UC_Z;
+               tzstr[1] = (char) 0;
+       }
+
+       /* Unlike year, the other parts fit into 16 bits so %d format
+        * is portable.
+        */
+       if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & 
DUK_DATE_FLAG_TOSTRING_TIME)) {
+               DUK_SPRINTF((char *) out_buf, 
"%s-%02d-%02d%c%02d:%02d:%02d.%03d%s",
+                           (const char *) yearstr, (int) 
parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY], (int) sep,
+                           (int) parts[DUK_DATE_IDX_HOUR], (int) 
parts[DUK_DATE_IDX_MINUTE],
+                           (int) parts[DUK_DATE_IDX_SECOND], (int) 
parts[DUK_DATE_IDX_MILLISECOND], (const char *) tzstr);
+       } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
+               DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d",
+                           (const char *) yearstr, (int) 
parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY]);
+       } else {
+               DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
+               DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s",
+                           (int) parts[DUK_DATE_IDX_HOUR], (int) 
parts[DUK_DATE_IDX_MINUTE],
+                           (int) parts[DUK_DATE_IDX_SECOND], (int) 
parts[DUK_DATE_IDX_MILLISECOND],
+                           (const char *) tzstr);
+       }
+}
+
+/* Helper for string conversion calls: check 'this' binding, get the
+ * internal time value, and format date and/or time in a few formats.
+ * Return value allows tail calls.
+ */
+DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t 
flags) {
+       duk_double_t d;
+       duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
+       duk_int_t tzoffset;  /* seconds, doesn't fit into 16 bits */
+       duk_bool_t rc;
+       duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE];
+
+       DUK_UNREF(rc);  /* unreferenced with some options */
+
+       d = duk__push_this_get_timeval_tzoffset(ctx, flags, &tzoffset);
+       if (DUK_ISNAN(d)) {
+               duk_push_hstring_stridx(ctx, DUK_STRIDX_INVALID_DATE);
+               return 1;
+       }
+       DUK_ASSERT(DUK_ISFINITE(d));
+
+       /* formatters always get one-based month/day-of-month */
+       duk_bi_date_timeval_to_parts(d, parts, NULL, DUK_DATE_FLAG_ONEBASED);
+       DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] 
<= 12);
+       DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 
31);
+
+       if (flags & DUK_DATE_FLAG_TOSTRING_LOCALE) {
+               /* try locale specific formatter; if it refuses to format the
+                * string, fall back to an ISO 8601 formatted value in local
+                * time.
+                */
+#if defined(DUK_USE_DATE_FORMAT_STRING)
+               /* Contract, either:
+                * - Push string to value stack and return 1
+                * - Don't push anything and return 0
+                */
+
+               rc = DUK_USE_DATE_FORMAT_STRING(ctx, parts, tzoffset, flags);
+               if (rc != 0) {
+                       return 1;
+               }
+#else
+               /* No locale specific formatter; this is OK, we fall back
+                * to ISO 8601.
+                */
+#endif
+       }
+
+       /* Different calling convention than above used because the helper
+        * is shared.
+        */
+       duk__format_parts_iso8601(parts, tzoffset, flags, buf);
+       duk_push_string(ctx, (const char *) buf);
+       return 1;
+}
+
+/* Helper for component getter calls: check 'this' binding, get the
+ * internal time value, split it into parts (either as UTC time or
+ * local time), push a specified component as a return value to the
+ * value stack and return 1 (caller can then tail call us).
+ */
+DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t 
flags_and_idx) {
+       duk_double_t d;
+       duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
+       duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> 
DUK_DATE_FLAG_VALUE_SHIFT);  /* unpack args */
+
+       DUK_ASSERT_DISABLE(idx_part >= 0);  /* unsigned */
+       DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
+
+       d = duk__push_this_get_timeval(ctx, flags_and_idx);
+       if (DUK_ISNAN(d)) {
+               duk_push_nan(ctx);
+               return 1;
+       }
+       DUK_ASSERT(DUK_ISFINITE(d));
+
+       duk_bi_date_timeval_to_parts(d, parts, NULL, flags_and_idx);  /* no 
need to mask idx portion */
+
+       /* Setter APIs detect special year numbers (0...99) and apply a +1900
+        * only in certain cases.  The legacy getYear() getter applies -1900
+        * unconditionally.
+        */
+       duk_push_int(ctx, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? 
parts[idx_part] - 1900 : parts[idx_part]);
+       return 1;
+}
+
+/* Helper for component setter calls: check 'this' binding, get the
+ * internal time value, split it into parts (either as UTC time or
+ * local time), modify one or more components as specified, recompute
+ * the time value, set it as the internal value.  Finally, push the
+ * new time value as a return value to the value stack and return 1
+ * (caller can then tail call us).
+ */
+DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t 
flags_and_maxnargs) {
+       duk_double_t d;
+       duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
+       duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
+       duk_idx_t nargs;
+       duk_small_uint_t maxnargs = (duk_small_uint_t) (flags_and_maxnargs >> 
DUK_DATE_FLAG_VALUE_SHIFT);  /* unpack args */
+       duk_small_uint_t idx_first, idx;
+       duk_small_uint_t i;
+
+       nargs = duk_get_top(ctx);
+       d = duk__push_this_get_timeval(ctx, flags_and_maxnargs);
+       DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
+
+       if (DUK_ISFINITE(d)) {
+               duk_bi_date_timeval_to_parts(d, parts, dparts, 
flags_and_maxnargs);
+       } else {
+               /* NaN timevalue: we need to coerce the arguments, but
+                * the resulting internal timestamp needs to remain NaN.
+                * This works but is not pretty: parts and dparts will
+                * be partially uninitialized, but we only write to them.
+                */
+       }
+
+       /*
+        *  Determining which datetime components to overwrite based on
+        *  stack arguments is a bit complicated, but important to factor
+        *  out from setters themselves for compactness.
+        *
+        *  If DUK_DATE_FLAG_TIMESETTER, maxnargs indicates setter type:
+        *
+        *   1 -> millisecond
+        *   2 -> second, [millisecond]
+        *   3 -> minute, [second], [millisecond]
+        *   4 -> hour, [minute], [second], [millisecond]
+        *
+        *  Else:
+        *
+        *   1 -> date
+        *   2 -> month, [date]
+        *   3 -> year, [month], [date]
+        *
+        *  By comparing nargs and maxnargs (and flags) we know which
+        *  components to override.  We rely on part index ordering.
+        */
+
+       if (flags_and_maxnargs & DUK_DATE_FLAG_TIMESETTER) {
+               DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4);
+               idx_first = DUK_DATE_IDX_MILLISECOND - (maxnargs - 1);
+       } else {
+               DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3);
+               idx_first = DUK_DATE_IDX_DAY - (maxnargs - 1);
+       }
+       DUK_ASSERT_DISABLE(idx_first >= 0);  /* unsigned */
+       DUK_ASSERT(idx_first < DUK_DATE_IDX_NUM_PARTS);
+
+       for (i = 0; i < maxnargs; i++) {
+               if ((duk_idx_t) i >= nargs) {
+                       /* no argument given -> leave components untouched */
+                       break;
+               }
+               idx = idx_first + i;
+               DUK_ASSERT_DISABLE(idx >= 0);  /* unsigned */
+               DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
+
+               if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & 
DUK_DATE_FLAG_YEAR_FIXUP)) {
+                       duk__twodigit_year_fixup(ctx, (duk_idx_t) i);
+               }
+
+               dparts[idx] = duk_to_number(ctx, i);
+
+               if (idx == DUK_DATE_IDX_DAY) {
+                       /* Day-of-month is one-based in the API, but zero-based
+                        * internally, so fix here.  Note that month is 
zero-based
+                        * both in the API and internally.
+                        */
+                       /* SCANBUILD: complains about use of uninitialized 
values.
+                        * The complaint is correct, but operating in undefined
+                        * values here is intentional in some cases and the 
caller
+                        * ignores the results.
+                        */
+                       dparts[idx] -= 1.0;
+               }
+       }
+
+       /* Leaves new timevalue on stack top and returns 1, which is correct
+        * for part setters.
+        */
+       if (DUK_ISFINITE(d)) {
+               return duk__set_this_timeval_from_dparts(ctx, dparts, 
flags_and_maxnargs);
+       } else {
+               /* Internal timevalue is already NaN, so don't touch it. */
+               duk_push_nan(ctx);
+               return 1;
+       }
+}
+
+/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
+ * 1900 and replace value at idx_val.
+ */
+DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
+       duk_double_t d;
+
+       /* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
+        * might not generate better code due to casting.
+        */
+
+       /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
+       duk_to_number(ctx, idx_val);
+       if (duk_is_nan(ctx, idx_val)) {
+               return;
+       }
+       duk_dup(ctx, idx_val);
+       duk_to_int(ctx, -1);
+       d = duk_get_number(ctx, -1);  /* get as double to handle huge numbers 
correctly */
+       if (d >= 0.0 && d <= 99.0) {
+               d += 1900.0;
+               duk_push_number(ctx, d);
+               duk_replace(ctx, idx_val);
+       }
+       duk_pop(ctx);
+}
+
+/* Set datetime parts from stack arguments, defaulting any missing values.
+ * Day-of-week is not set; it is not required when setting the time value.
+ */
+DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t 
*dparts, duk_idx_t nargs) {
+       duk_double_t d;
+       duk_small_uint_t i;
+       duk_small_uint_t idx;
+
+       /* Causes a ToNumber() coercion, but doesn't break coercion order since
+        * year is coerced first anyway.
+        */
+       duk__twodigit_year_fixup(ctx, 0);
+
+       /* There are at most 7 args, but we use 8 here so that also
+        * DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the 
potential
+        * for any Valgrind gripes later.
+        */
+       for (i = 0; i < 8; i++) {
+               /* Note: rely on index ordering */
+               idx = DUK_DATE_IDX_YEAR + i;
+               if ((duk_idx_t) i < nargs) {
+                       d = duk_to_number(ctx, (duk_idx_t) i);
+                       if (idx == DUK_DATE_IDX_DAY) {
+                               /* Convert day from one-based to zero-based 
(internal).  This may
+                                * cause the day part to be negative, which is 
OK.
+                                */
+                               d -= 1.0;
+                       }
+               } else {
+                       /* All components default to 0 except day-of-month 
which defaults
+                        * to 1.  However, because our internal day-of-month is 
zero-based,
+                        * it also defaults to zero here.
+                        */
+                       d = 0.0;
+               }
+               dparts[idx] = d;
+       }
+
+       DUK_DDD(DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf 
%lf",
+                            (double) dparts[0], (double) dparts[1],
+                            (double) dparts[2], (double) dparts[3],
+                            (double) dparts[4], (double) dparts[5],
+                            (double) dparts[6], (double) dparts[7]));
+}
+
+/*
+ *  Helper to format a time value into caller buffer, used by logging.
+ *  'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long.
+ */
+
+DUK_INTERNAL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t 
*out_buf) {
+       duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
+
+       duk_bi_date_timeval_to_parts(timeval,
+                                    parts,
+                                    NULL,
+                                    DUK_DATE_FLAG_ONEBASED);
+
+       duk__format_parts_iso8601(parts,
+                                 0 /*tzoffset*/,
+                                 DUK_DATE_FLAG_TOSTRING_DATE |
+                                 DUK_DATE_FLAG_TOSTRING_TIME |
+                                 DUK_DATE_FLAG_SEP_T /*flags*/,
+                                 out_buf);
+}
+
+/*
+ *  Indirect magic value lookup for Date methods.
+ *
+ *  Date methods don't put their control flags into the function magic value
+ *  because they wouldn't fit into a LIGHTFUNC's magic field.  Instead, the
+ *  magic value is set to an index pointing to the array of control flags
+ *  below.
+ *
+ *  This must be kept in strict sync with genbuiltins.py!
+ */
+
+static duk_uint16_t duk__date_magics[] = {
+       /* 0: toString */
+       DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + 
DUK_DATE_FLAG_LOCALTIME,
+
+       /* 1: toDateString */
+       DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_LOCALTIME,
+
+       /* 2: toTimeString */
+       DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
+
+       /* 3: toLocaleString */
+       DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + 
DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
+
+       /* 4: toLocaleDateString */
+       DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_LOCALE + 
DUK_DATE_FLAG_LOCALTIME,
+
+       /* 5: toLocaleTimeString */
+       DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + 
DUK_DATE_FLAG_LOCALTIME,
+
+       /* 6: toUTCString */
+       DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME,
+
+       /* 7: toISOString */
+       DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + 
DUK_DATE_FLAG_NAN_TO_RANGE_ERROR + DUK_DATE_FLAG_SEP_T,
+
+       /* 8: getFullYear */
+       DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_YEAR << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 9: getUTCFullYear */
+       0 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 10: getMonth */
+       DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MONTH << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 11: getUTCMonth */
+       0 + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 12: getDate */
+       DUK_DATE_FLAG_ONEBASED + DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_DAY << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 13: getUTCDate */
+       DUK_DATE_FLAG_ONEBASED + (DUK_DATE_IDX_DAY << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 14: getDay */
+       DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_WEEKDAY << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 15: getUTCDay */
+       0 + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 16: getHours */
+       DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_HOUR << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 17: getUTCHours */
+       0 + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 18: getMinutes */
+       DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MINUTE << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 19: getUTCMinutes */
+       0 + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 20: getSeconds */
+       DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_SECOND << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 21: getUTCSeconds */
+       0 + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 22: getMilliseconds */
+       DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MILLISECOND << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 23: getUTCMilliseconds */
+       0 + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 24: setMilliseconds */
+       DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (1 << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 25: setUTCMilliseconds */
+       DUK_DATE_FLAG_TIMESETTER + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 26: setSeconds */
+       DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (2 << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 27: setUTCSeconds */
+       DUK_DATE_FLAG_TIMESETTER + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 28: setMinutes */
+       DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (3 << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 29: setUTCMinutes */
+       DUK_DATE_FLAG_TIMESETTER + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 30: setHours */
+       DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (4 << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 31: setUTCHours */
+       DUK_DATE_FLAG_TIMESETTER + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 32: setDate */
+       DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 33: setUTCDate */
+       0 + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 34: setMonth */
+       DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 35: setUTCMonth */
+       0 + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 36: setFullYear */
+       DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_LOCALTIME + (3 << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 37: setUTCFullYear */
+       DUK_DATE_FLAG_NAN_TO_ZERO + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 38: getYear */
+       DUK_DATE_FLAG_LOCALTIME + DUK_DATE_FLAG_SUB1900 + (DUK_DATE_IDX_YEAR << 
DUK_DATE_FLAG_VALUE_SHIFT),
+
+       /* 39: setYear */
+       DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << 
DUK_DATE_FLAG_VALUE_SHIFT),
+};
+
+DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) {
+       duk_small_int_t magicidx = (duk_small_uint_t) 
duk_get_current_magic(ctx);
+       DUK_ASSERT(magicidx >= 0 && magicidx < (duk_small_int_t) 
(sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
+       return (duk_small_uint_t) duk__date_magics[magicidx];
+}
+
+/*
+ *  Constructor calls
+ */
+
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) {
+       duk_idx_t nargs = duk_get_top(ctx);
+       duk_bool_t is_cons = duk_is_constructor_call(ctx);
+       duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
+       duk_double_t d;
+
+       DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) 
nargs, (long) is_cons));
+
+       duk_push_object_helper(ctx,
+                              DUK_HOBJECT_FLAG_EXTENSIBLE |
+                              
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
+                              DUK_BIDX_DATE_PROTOTYPE);
+
+       /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
+        * is mutable.
+        */
+
+       if (nargs == 0 || !is_cons) {
+               d = duk__timeclip(DUK_USE_DATE_GET_NOW(ctx));
+               duk_push_number(ctx, d);
+               duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, 
DUK_PROPDESC_FLAGS_W);
+               if (!is_cons) {
+                       /* called as a normal function: return new 
Date().toString() */
+                       duk_to_string(ctx, -1);
+               }
+               return 1;
+       } else if (nargs == 1) {
+               duk_to_primitive(ctx, 0, DUK_HINT_NONE);
+               if (duk_is_string(ctx, 0)) {
+                       duk__parse_string(ctx, duk_to_string(ctx, 0));
+                       duk_replace(ctx, 0);  /* may be NaN */
+               }
+               d = duk__timeclip(duk_to_number(ctx, 0));
+               duk_push_number(ctx, d);
+               duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, 
DUK_PROPDESC_FLAGS_W);
+               return 1;
+       }
+
+       duk__set_parts_from_args(ctx, dparts, nargs);
+
+       /* Parts are in local time, convert when setting. */
+
+       (void) duk__set_this_timeval_from_dparts(ctx, dparts, 
DUK_DATE_FLAG_LOCALTIME /*flags*/);  /* -> [ ... this timeval ] */
+       duk_pop(ctx);  /* -> [ ... this ] */
+       return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx) {
+       return duk__parse_string(ctx, duk_to_string(ctx, 0));
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
+       duk_idx_t nargs = duk_get_top(ctx);
+       duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
+       duk_double_t d;
+
+       /* Behavior for nargs < 2 is implementation dependent: currently we'll
+        * set a NaN time value (matching V8 behavior) in this case.
+        */
+
+       if (nargs < 2) {
+               duk_push_nan(ctx);
+       } else {
+               duk__set_parts_from_args(ctx, dparts, nargs);
+               d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
+               duk_push_number(ctx, d);
+       }
+       return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
+       duk_double_t d;
+
+       d = DUK_USE_DATE_GET_NOW(ctx);
+       DUK_ASSERT(duk__timeclip(d) == d);  /* TimeClip() should never be 
necessary */
+       duk_push_number(ctx, d);
+       return 1;
+}
+
+/*
+ *  String/JSON conversions
+ *
+ *  Human readable conversions are now basically ISO 8601 with a space
+ *  (instead of 'T') as the date/time separator.  This is a good baseline
+ *  and is platform independent.
+ *
+ *  A shared native helper to provide many conversions.  Magic value contains
+ *  a set of flags.  The helper provides:
+ *
+ *    toString()
+ *    toDateString()
+ *    toTimeString()
+ *    toLocaleString()
+ *    toLocaleDateString()
+ *    toLocaleTimeString()
+ *    toUTCString()
+ *    toISOString()
+ *
+ *  Notes:
+ *
+ *    - Date.prototype.toGMTString() and Date.prototype.toUTCString() are
+ *      required to be the same Ecmascript function object (!), so it is
+ *      omitted from here.
+ *
+ *    - Date.prototype.toUTCString(): E5.1 specification does not require a
+ *      specific format, but result should be human readable.  The
+ *      specification suggests using ISO 8601 format with a space (instead
+ *      of 'T') separator if a more human readable format is not available.
+ *
+ *    - Date.prototype.toISOString(): unlike other conversion functions,
+ *      toISOString() requires a RangeError for invalid date values.
+ */
+
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx) 
{
+       duk_small_uint_t flags = duk__date_get_indirect_magic(ctx);
+       return duk__to_string_helper(ctx, flags);
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx) {
+       /* This native function is also used for Date.prototype.getTime()
+        * as their behavior is identical.
+        */
+
+       duk_double_t d = duk__push_this_get_timeval(ctx, 0 /*flags*/);  /* -> [ 
this ] */
+       DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
+       duk_push_number(ctx, d);
+       return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
+       /* Note: toJSON() is a generic function which works even if 'this'
+        * is not a Date.  The sole argument is ignored.
+        */
+
+       duk_push_this(ctx);
+       duk_to_object(ctx, -1);
+
+       duk_dup_top(ctx);
+       duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
+       if (duk_is_number(ctx, -1)) {
+               duk_double_t d = duk_get_number(ctx, -1);
+               if (!DUK_ISFINITE(d)) {
+                       duk_push_null(ctx);
+                       return 1;
+               }
+       }
+       duk_pop(ctx);
+
+       duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_ISO_STRING);
+       duk_dup(ctx, -2);  /* -> [ O toIsoString O ] */
+       duk_call_method(ctx, 0);
+       return 1;
+}
+
+/*
+ *  Getters.
+ *
+ *  Implementing getters is quite easy.  The internal time value is either
+ *  NaN, or represents milliseconds (without fractions) from Jan 1, 1970.
+ *  The internal time value can be converted to integer parts, and each
+ *  part will be normalized and will fit into a 32-bit signed integer.
+ *
+ *  A shared native helper to provide all getters.  Magic value contains
+ *  a set of flags and also packs the date component index argument.  The
+ *  helper provides:
+ *
+ *    getFullYear()
+ *    getUTCFullYear()
+ *    getMonth()
+ *    getUTCMonth()
+ *    getDate()
+ *    getUTCDate()
+ *    getDay()
+ *    getUTCDay()
+ *    getHours()
+ *    getUTCHours()
+ *    getMinutes()
+ *    getUTCMinutes()
+ *    getSeconds()
+ *    getUTCSeconds()
+ *    getMilliseconds()
+ *    getUTCMilliseconds()
+ *    getYear()
+ *
+ *  Notes:
+ *
+ *    - Date.prototype.getDate(): 'date' means day-of-month, and is
+ *      zero-based in internal calculations but public API expects it to
+ *      be one-based.
+ *
+ *    - Date.prototype.getTime() and Date.prototype.valueOf() have identical
+ *      behavior.  They have separate function objects, but share the same C
+ *      function (duk_bi_date_prototype_value_of).
+ */
+
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx) {
+       duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(ctx);
+       return duk__get_part_helper(ctx, flags_and_idx);
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context 
*ctx) {
+       /*
+        *  Return (t - LocalTime(t)) in minutes:
+        *
+        *    t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t))
+        *                     = -(LocalTZA + DaylightSavingTA(t))
+        *
+        *  where DaylightSavingTA() is checked for time 't'.
+        *
+        *  Note that the sign of the result is opposite to common usage,
+        *  e.g. for EE(S)T which normally is +2h or +3h from UTC, this
+        *  function returns -120 or -180.
+        *
+        */
+
+       duk_double_t d;
+       duk_int_t tzoffset;
+
+       /* Note: DST adjustment is determined using UTC time. */
+       d = duk__push_this_get_timeval(ctx, 0 /*flags*/);
+       DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
+       if (DUK_ISNAN(d)) {
+               duk_push_nan(ctx);
+       } else {
+               DUK_ASSERT(DUK_ISFINITE(d));
+               tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
+               duk_push_int(ctx, -tzoffset / 60);
+       }
+       return 1;
+}
+
+/*
+ *  Setters.
+ *
+ *  Setters are a bit more complicated than getters.  Component setters
+ *  break down the current time value into its (normalized) component
+ *  parts, replace one or more components with -unnormalized- new values,
+ *  and the components are then converted back into a time value.  As an
+ *  example of using unnormalized values:
+ *
+ *    var d = new Date(1234567890);
+ *
+ *  is equivalent to:
+ *
+ *    var d = new Date(0);
+ *    d.setUTCMilliseconds(1234567890);
+ *
+ *  A shared native helper to provide almost all setters.  Magic value
+ *  contains a set of flags and also packs the "maxnargs" argument.  The
+ *  helper provides:
+ *
+ *    setMilliseconds()
+ *    setUTCMilliseconds()
+ *    setSeconds()
+ *    setUTCSeconds()
+ *    setMinutes()
+ *    setUTCMinutes()
+ *    setHours()
+ *    setUTCHours()
+ *    setDate()
+ *    setUTCDate()
+ *    setMonth()
+ *    setUTCMonth()
+ *    setFullYear()
+ *    setUTCFullYear()
+ *    setYear()
+ *
+ *  Notes:
+ *
+ *    - Date.prototype.setYear() (Section B addition): special year check
+ *      is omitted.  NaN / Infinity will just flow through and ultimately
+ *      result in a NaN internal time value.
+ *
+ *    - Date.prototype.setYear() does not have optional arguments for
+ *      setting month and day-in-month (like setFullYear()), but we indicate
+ *      'maxnargs' to be 3 to get the year written to the correct component
+ *      index in duk__set_part_helper().  The function has nargs == 1, so only
+ *      the year will be set regardless of actual argument count.
+ */
+
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx) {
+       duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(ctx);
+       return duk__set_part_helper(ctx, flags_and_maxnargs);
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
+       duk_double_t d;
+
+       (void) duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ timeval 
this ] */
+       d = duk__timeclip(duk_to_number(ctx, 0));
+       duk_push_number(ctx, d);
+       duk_dup_top(ctx);
+       duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval 
this timeval ] */
+
+       return 1;
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date_unix.c
----------------------------------------------------------------------
diff --git 
a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date_unix.c
 
b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date_unix.c
new file mode 100644
index 0000000..e1e7c42
--- /dev/null
+++ 
b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date_unix.c
@@ -0,0 +1,309 @@
+/*
+ *  Unix-like Date providers
+ *
+ *  Generally useful Unix / POSIX / ANSI Date providers.
+ */
+
+#include "duk_internal.h"
+
+/* The necessary #includes are in place in duk_config.h. */
+
+/* Buffer sizes for some UNIX calls.  Larger than strictly necessary
+ * to avoid Valgrind errors.
+ */
+#define DUK__STRPTIME_BUF_SIZE  64
+#define DUK__STRFTIME_BUF_SIZE  64
+
+#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
+/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
+       duk_hthread *thr = (duk_hthread *) ctx;
+       struct timeval tv;
+       duk_double_t d;
+
+       if (gettimeofday(&tv, NULL) != 0) {
+               DUK_ERROR_INTERNAL_DEFMSG(thr);
+       }
+
+       d = ((duk_double_t) tv.tv_sec) * 1000.0 +
+           ((duk_double_t) (tv.tv_usec / 1000));
+       DUK_ASSERT(DUK_FLOOR(d) == d);  /* no fractions */
+
+       return d;
+}
+#endif  /* DUK_USE_DATE_NOW_GETTIMEOFDAY */
+
+#if defined(DUK_USE_DATE_NOW_TIME)
+/* Not a very good provider: only full seconds are available. */
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) {
+       time_t t;
+
+       DUK_UNREF(ctx);
+       t = time(NULL);
+       return ((duk_double_t) t) * 1000.0;
+}
+#endif  /* DUK_USE_DATE_NOW_TIME */
+
+#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R)
+/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
+DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
+       time_t t, t1, t2;
+       duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
+       duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
+       struct tm tms[2];
+#ifdef DUK_USE_DATE_TZO_GMTIME
+       struct tm *tm_ptr;
+#endif
+
+       /* For NaN/inf, the return value doesn't matter. */
+       if (!DUK_ISFINITE(d)) {
+               return 0;
+       }
+
+       /* If not within Ecmascript range, some integer time calculations
+        * won't work correctly (and some asserts will fail), so bail out
+        * if so.  This fixes test-bug-date-insane-setyear.js.  There is
+        * a +/- 24h leeway in this range check to avoid a test262 corner
+        * case documented in test-bug-date-timeval-edges.js.
+        */
+       if (!duk_bi_date_timeval_in_leeway_range(d)) {
+               DUK_DD(DUK_DDPRINT("timeval not within valid range, skip 
tzoffset computation to avoid integer overflows"));
+               return 0;
+       }
+
+       /*
+        *  This is a bit tricky to implement portably.  The result depends
+        *  on the timestamp (specifically, DST depends on the timestamp).
+        *  If e.g. UNIX APIs are used, they'll have portability issues with
+        *  very small and very large years.
+        *
+        *  Current approach:
+        *
+        *  - Stay within portable UNIX limits by using equivalent year mapping.
+        *    Avoid year 1970 and 2038 as some conversions start to fail, at
+        *    least on some platforms.  Avoiding 1970 means that there are
+        *    currently DST discrepancies for 1970.
+        *
+        *  - Create a UTC and local time breakdowns from 't'.  Then create
+        *    a time_t using gmtime() and localtime() and compute the time
+        *    difference between the two.
+        *
+        *  Equivalent year mapping (E5 Section 15.9.1.8):
+        *
+        *    If the host environment provides functionality for determining
+        *    daylight saving time, the implementation of ECMAScript is free
+        *    to map the year in question to an equivalent year (same
+        *    leap-year-ness and same starting week day for the year) for which
+        *    the host environment provides daylight saving time information.
+        *    The only restriction is that all equivalent years should produce
+        *    the same result.
+        *
+        *  This approach is quite reasonable but not entirely correct, e.g.
+        *  the specification also states (E5 Section 15.9.1.8):
+        *
+        *    The implementation of ECMAScript should not try to determine
+        *    whether the exact time was subject to daylight saving time, but
+        *    just whether daylight saving time would have been in effect if
+        *    the _current daylight saving time algorithm_ had been used at the
+        *    time.  This avoids complications such as taking into account the
+        *    years that the locale observed daylight saving time year round.
+        *
+        *  Since we rely on the platform APIs for conversions between local
+        *  time and UTC, we can't guarantee the above.  Rather, if the platform
+        *  has historical DST rules they will be applied.  This seems to be the
+        *  general preferred direction in Ecmascript standardization (or at 
least
+        *  implementations) anyway, and even the equivalent year mapping should
+        *  be disabled if the platform is known to handle DST properly for the
+        *  full Ecmascript range.
+        *
+        *  The following has useful discussion and links:
+        *
+        *    https://bugzilla.mozilla.org/show_bug.cgi?id=351066
+        */
+
+       duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR 
/*flags*/);
+       DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] 
<= 2038);
+
+       d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
+       DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0);  /* unsigned 31-bit 
range */
+       t = (time_t) (d / 1000.0);
+       DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) 
t));
+
+       DUK_MEMZERO((void *) tms, sizeof(struct tm) * 2);
+
+#if defined(DUK_USE_DATE_TZO_GMTIME_R)
+       (void) gmtime_r(&t, &tms[0]);
+       (void) localtime_r(&t, &tms[1]);
+#elif defined(DUK_USE_DATE_TZO_GMTIME)
+       tm_ptr = gmtime(&t);
+       DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm));
+       tm_ptr = localtime(&t);
+       DUK_MEMCPY((void *) &tms[1], tm_ptr, sizeof(struct tm));
+#else
+#error internal error
+#endif
+       DUK_DDD(DUK_DDDPRINT("gmtime result: 
tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
+                            "wday:%ld,yday:%ld,isdst:%ld}",
+                            (long) tms[0].tm_sec, (long) tms[0].tm_min, (long) 
tms[0].tm_hour,
+                            (long) tms[0].tm_mday, (long) tms[0].tm_mon, 
(long) tms[0].tm_year,
+                            (long) tms[0].tm_wday, (long) tms[0].tm_yday, 
(long) tms[0].tm_isdst));
+       DUK_DDD(DUK_DDDPRINT("localtime result: 
tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
+                            "wday:%ld,yday:%ld,isdst:%ld}",
+                            (long) tms[1].tm_sec, (long) tms[1].tm_min, (long) 
tms[1].tm_hour,
+                            (long) tms[1].tm_mday, (long) tms[1].tm_mon, 
(long) tms[1].tm_year,
+                            (long) tms[1].tm_wday, (long) tms[1].tm_yday, 
(long) tms[1].tm_isdst));
+
+       /* tm_isdst is both an input and an output to mktime(), use 0 to
+        * avoid DST handling in mktime():
+        * - https://github.com/svaarala/duktape/issues/406
+        * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
+        */
+       tms[0].tm_isdst = 0;
+       tms[1].tm_isdst = 0;
+       t1 = mktime(&tms[0]);  /* UTC */
+       t2 = mktime(&tms[1]);  /* local */
+       if (t1 == (time_t) -1 || t2 == (time_t) -1) {
+               /* This check used to be for (t < 0) but on some platforms
+                * time_t is unsigned and apparently the proper way to detect
+                * an mktime() error return is the cast above.  See e.g.:
+                * 
http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
+                */
+               goto error;
+       }
+       DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) 
t2));
+
+       /* Compute final offset in seconds, positive if local time ahead of
+        * UTC (returned value is UTC-to-local offset).
+        *
+        * difftime() returns a double, so coercion to int generates quite
+        * a lot of code.  Direct subtraction is not portable, however.
+        * XXX: allow direct subtraction on known platforms.
+        */
+#if 0
+       return (duk_int_t) (t2 - t1);
+#endif
+       return (duk_int_t) difftime(t2, t1);
+
+ error:
+       /* XXX: return something more useful, so that caller can throw? */
+       DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
+       return 0;
+}
+#endif  /* DUK_USE_DATE_TZO_GMTIME */
+
+#if defined(DUK_USE_DATE_PRS_STRPTIME)
+DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, 
const char *str) {
+       struct tm tm;
+       time_t t;
+       char buf[DUK__STRPTIME_BUF_SIZE];
+
+       /* copy to buffer with spare to avoid Valgrind gripes from strptime */
+       DUK_ASSERT(str != NULL);
+       DUK_MEMZERO(buf, sizeof(buf));  /* valgrind whine without this */
+       DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
+       buf[sizeof(buf) - 1] = (char) 0;
+
+       DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf));
+
+       DUK_MEMZERO(&tm, sizeof(tm));
+       if (strptime((const char *) buf, "%c", &tm) != NULL) {
+               DUK_DDD(DUK_DDDPRINT("before mktime: 
tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
+                                    "wday:%ld,yday:%ld,isdst:%ld}",
+                                    (long) tm.tm_sec, (long) tm.tm_min, (long) 
tm.tm_hour,
+                                    (long) tm.tm_mday, (long) tm.tm_mon, 
(long) tm.tm_year,
+                                    (long) tm.tm_wday, (long) tm.tm_yday, 
(long) tm.tm_isdst));
+               tm.tm_isdst = -1;  /* negative: dst info not available */
+
+               t = mktime(&tm);
+               DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
+               if (t >= 0) {
+                       duk_push_number(ctx, ((duk_double_t) t) * 1000.0);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+#endif  /* DUK_USE_DATE_PRS_STRPTIME */
+
+#if defined(DUK_USE_DATE_PRS_GETDATE)
+DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, 
const char *str) {
+       struct tm tm;
+       duk_small_int_t rc;
+       time_t t;
+
+       /* For this to work, DATEMSK must be set, so this is not very
+        * convenient for an embeddable interpreter.
+        */
+
+       DUK_MEMZERO(&tm, sizeof(struct tm));
+       rc = (duk_small_int_t) getdate_r(str, &tm);
+       DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc));
+
+       if (rc == 0) {
+               t = mktime(&tm);
+               DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
+               if (t >= 0) {
+                       duk_push_number(ctx, (duk_double_t) t);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+#endif  /* DUK_USE_DATE_PRS_GETDATE */
+
+#if defined(DUK_USE_DATE_FMT_STRFTIME)
+DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, 
duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) {
+       char buf[DUK__STRFTIME_BUF_SIZE];
+       struct tm tm;
+       const char *fmt;
+
+       DUK_UNREF(tzoffset);
+
+       /* If the platform doesn't support the entire Ecmascript range, we need
+        * to return 0 so that the caller can fall back to the default 
formatter.
+        *
+        * For now, assume that if time_t is 8 bytes or more, the whole 
Ecmascript
+        * range is supported.  For smaller time_t values (4 bytes in practice),
+        * assumes that the signed 32-bit range is supported.
+        *
+        * XXX: detect this more correctly per platform.  The size of time_t is
+        * probably not an accurate guarantee of strftime() supporting or not
+        * supporting a large time range (the full Ecmascript range).
+        */
+       if (sizeof(time_t) < 8 &&
+          (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 
2037)) {
+               /* be paranoid for 32-bit time values (even avoiding negative 
ones) */
+               return 0;
+       }
+
+       DUK_MEMZERO(&tm, sizeof(tm));
+       tm.tm_sec = parts[DUK_DATE_IDX_SECOND];
+       tm.tm_min = parts[DUK_DATE_IDX_MINUTE];
+       tm.tm_hour = parts[DUK_DATE_IDX_HOUR];
+       tm.tm_mday = parts[DUK_DATE_IDX_DAY];       /* already one-based */
+       tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1;  /* one-based -> zero-based 
*/
+       tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900;
+       tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY];
+       tm.tm_isdst = 0;
+
+       DUK_MEMZERO(buf, sizeof(buf));
+       if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & 
DUK_DATE_FLAG_TOSTRING_TIME)) {
+               fmt = "%c";
+       } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
+               fmt = "%x";
+       } else {
+               DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
+               fmt = "%X";
+       }
+       (void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
+       DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
+
+       duk_push_string(ctx, buf);
+       return 1;
+}
+#endif  /* DUK_USE_DATE_FMT_STRFTIME */
+
+#undef DUK__STRPTIME_BUF_SIZE
+#undef DUK__STRFTIME_BUF_SIZE

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date_windows.c
----------------------------------------------------------------------
diff --git 
a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date_windows.c
 
b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date_windows.c
new file mode 100644
index 0000000..c131d22
--- /dev/null
+++ 
b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_date_windows.c
@@ -0,0 +1,98 @@
+/*
+ *  Windows Date providers
+ *
+ *  Platform specific links:
+ *
+ *    - 
http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
+ */
+
+#include "duk_internal.h"
+
+/* The necessary #includes are in place in duk_config.h. */
+
+#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
+/* Shared Windows helpers. */
+DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, 
ULARGE_INTEGER *res) {
+       FILETIME ft;
+       if (SystemTimeToFileTime(st, &ft) == 0) {
+               DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
+               res->QuadPart = 0;
+       } else {
+               res->LowPart = ft.dwLowDateTime;
+               res->HighPart = ft.dwHighDateTime;
+       }
+}
+DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
+       DUK_MEMZERO((void *) st, sizeof(*st));
+       st->wYear = 1970;
+       st->wMonth = 1;
+       st->wDayOfWeek = 4;  /* not sure whether or not needed; Thursday */
+       st->wDay = 1;
+       DUK_ASSERT(st->wHour == 0);
+       DUK_ASSERT(st->wMinute == 0);
+       DUK_ASSERT(st->wSecond == 0);
+       DUK_ASSERT(st->wMilliseconds == 0);
+}
+#endif  /* defined(DUK_USE_DATE_NOW_WINDOWS) || 
defined(DUK_USE_DATE_TZO_WINDOWS) */
+
+#ifdef DUK_USE_DATE_NOW_WINDOWS
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) {
+       /* Suggested step-by-step method from documentation of 
RtlTimeToSecondsSince1970:
+        * 
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
+        */
+       SYSTEMTIME st1, st2;
+       ULARGE_INTEGER tmp1, tmp2;
+
+       DUK_UNREF(ctx);
+
+       GetSystemTime(&st1);
+       duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
+
+       duk__set_systime_jan1970(&st2);
+       duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
+
+       /* Difference is in 100ns units, convert to milliseconds w/o fractions 
*/
+       return (duk_double_t) ((tmp1.QuadPart - tmp2.QuadPart) / 10000LL);
+}
+#endif  /* DUK_USE_DATE_NOW_WINDOWS */
+
+
+#if defined(DUK_USE_DATE_TZO_WINDOWS)
+DUK_INTERNAL_DECL duk_int_t 
duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
+       SYSTEMTIME st1;
+       SYSTEMTIME st2;
+       SYSTEMTIME st3;
+       ULARGE_INTEGER tmp1;
+       ULARGE_INTEGER tmp2;
+       ULARGE_INTEGER tmp3;
+       FILETIME ft1;
+
+       /* XXX: handling of timestamps outside Windows supported range.
+        * How does Windows deal with dates before 1600?  Does windows
+        * support all Ecmascript years (like -200000 and +200000)?
+        * Should equivalent year mapping be used here too?  If so, use
+        * a shared helper (currently integrated into timeval-to-parts).
+        */
+
+       /* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
+        * 
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
+        */
+
+       duk__set_systime_jan1970(&st1);
+       duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
+       tmp2.QuadPart = (ULONGLONG) (d * 10000.0);  /* millisec -> 100ns units 
since jan 1, 1970 */
+       tmp2.QuadPart += tmp1.QuadPart;             /* input 'd' in Windows 
UTC, 100ns units */
+
+       ft1.dwLowDateTime = tmp2.LowPart;
+       ft1.dwHighDateTime = tmp2.HighPart;
+       FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
+       if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, 
&st2, &st3) == 0) {
+               DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, 
return tzoffset 0"));
+               return 0;
+       }
+       duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
+
+       /* Positive if local time ahead of UTC. */
+       return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) 
tmp2.QuadPart) / 10000000LL);  /* seconds */
+}
+#endif  /* DUK_USE_DATE_TZO_WINDOWS */

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_duktape.c
----------------------------------------------------------------------
diff --git 
a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_duktape.c
 
b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_duktape.c
new file mode 100644
index 0000000..79d6919
--- /dev/null
+++ 
b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_bi_duktape.c
@@ -0,0 +1,321 @@
+/*
+ *  Duktape built-ins
+ *
+ *  Size optimization note: it might seem that vararg multipurpose functions
+ *  like fin(), enc(), and dec() are not very size optimal, but using a single
+ *  user-visible Ecmascript function saves a lot of run-time footprint; each
+ *  Function instance takes >100 bytes.  Using a shared native helper and a
+ *  'magic' value won't save much if there are multiple Function instances
+ *  anyway.
+ */
+
+#include "duk_internal.h"
+
+/* Raw helper to extract internal information / statistics about a value.
+ * The return values are version specific and must not expose anything
+ * that would lead to security issues (e.g. exposing compiled function
+ * 'data' buffer might be an issue).  Currently only counts and sizes and
+ * such are given so there should not be a security impact.
+ */
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
+       duk_hthread *thr = (duk_hthread *) ctx;
+       duk_tval *tv;
+       duk_heaphdr *h;
+       duk_int_t i, n;
+
+       DUK_UNREF(thr);
+
+       /* result array */
+       duk_push_array(ctx);  /* -> [ val arr ] */
+
+       /* type tag (public) */
+       duk_push_int(ctx, duk_get_type(ctx, 0));
+
+       /* address */
+       tv = duk_get_tval(ctx, 0);
+       DUK_ASSERT(tv != NULL);  /* because arg count is 1 */
+       if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
+               h = DUK_TVAL_GET_HEAPHDR(tv);
+               duk_push_pointer(ctx, (void *) h);
+       } else {
+               /* internal type tag */
+               duk_push_int(ctx, (duk_int_t) DUK_TVAL_GET_TAG(tv));
+               goto done;
+       }
+       DUK_ASSERT(h != NULL);
+
+       /* refcount */
+#ifdef DUK_USE_REFERENCE_COUNTING
+       duk_push_size_t(ctx, DUK_HEAPHDR_GET_REFCOUNT(h));
+#else
+       duk_push_undefined(ctx);
+#endif
+
+       /* heaphdr size and additional allocation size, followed by
+        * type specific stuff (with varying value count)
+        */
+       switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
+       case DUK_HTYPE_STRING: {
+               duk_hstring *h_str = (duk_hstring *) h;
+               duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hstring) + 
DUK_HSTRING_GET_BYTELEN(h_str) + 1));
+               break;
+       }
+       case DUK_HTYPE_OBJECT: {
+               duk_hobject *h_obj = (duk_hobject *) h;
+               duk_small_uint_t hdr_size;
+               if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
+                       hdr_size = (duk_small_uint_t) 
sizeof(duk_hcompiledfunction);
+               } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
+                       hdr_size = (duk_small_uint_t) 
sizeof(duk_hnativefunction);
+               } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
+                       hdr_size = (duk_small_uint_t) sizeof(duk_hthread);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+               } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
+                       hdr_size = (duk_small_uint_t) sizeof(duk_hbufferobject);
+#endif
+               } else {
+                       hdr_size = (duk_small_uint_t) sizeof(duk_hobject);
+               }
+               duk_push_uint(ctx, (duk_uint_t) hdr_size);
+               duk_push_uint(ctx, (duk_uint_t) 
DUK_HOBJECT_P_ALLOC_SIZE(h_obj));
+               duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
+               /* Note: e_next indicates the number of gc-reachable entries
+                * in the entry part, and also indicates the index where the
+                * next new property would be inserted.  It does *not* indicate
+                * the number of non-NULL keys present in the object.  That
+                * value could be counted separately but requires a pass through
+                * the key list.
+                */
+               duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
+               duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
+               duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
+               if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
+                       duk_hbuffer *h_data = (duk_hbuffer *) 
DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, (duk_hcompiledfunction *) h_obj);
+                       if (h_data) {
+                               duk_push_uint(ctx, (duk_uint_t) 
DUK_HBUFFER_GET_SIZE(h_data));
+                       } else {
+                               duk_push_uint(ctx, 0);
+                       }
+               }
+               break;
+       }
+       case DUK_HTYPE_BUFFER: {
+               duk_hbuffer *h_buf = (duk_hbuffer *) h;
+               if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
+                       if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
+                               duk_push_uint(ctx, (duk_uint_t) 
(sizeof(duk_hbuffer_external)));
+                       } else {
+                               /* When alloc_size == 0 the second allocation 
may not
+                                * actually exist.
+                                */
+                               duk_push_uint(ctx, (duk_uint_t) 
(sizeof(duk_hbuffer_dynamic)));
+                       }
+                       duk_push_uint(ctx, (duk_uint_t) 
(DUK_HBUFFER_GET_SIZE(h_buf)));
+               } else {
+                       duk_push_uint(ctx, (duk_uint_t) 
(sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1));
+               }
+               break;
+
+       }
+       }
+
+ done:
+       /* set values into ret array */
+       /* XXX: primitive to make array from valstack slice */
+       n = duk_get_top(ctx);
+       for (i = 2; i < n; i++) {
+               duk_dup(ctx, i);
+               duk_put_prop_index(ctx, 1, i - 2);
+       }
+       duk_dup(ctx, 1);
+       return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
+       duk_hthread *thr = (duk_hthread *) ctx;
+       duk_activation *act;
+       duk_uint_fast32_t pc;
+       duk_uint_fast32_t line;
+       duk_int_t level;
+
+       /* -1             = top callstack entry, callstack[callstack_top - 1]
+        * -callstack_top = bottom callstack entry, callstack[0]
+        */
+       level = duk_to_int(ctx, 0);
+       if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
+               return 0;
+       }
+       DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
+       act = thr->callstack + thr->callstack_top + level;
+
+       duk_push_object(ctx);
+
+       duk_push_tval(ctx, &act->tv_func);
+
+       /* Relevant PC is just before current one because PC is
+        * post-incremented.  This should match what error augment
+        * code does.
+        */
+       pc = duk_hthread_get_act_prev_pc(thr, act);
+       duk_push_uint(ctx, (duk_uint_t) pc);
+
+#if defined(DUK_USE_PC2LINE)
+       line = duk_hobject_pc2line_query(ctx, -2, pc);
+#else
+       line = 0;
+#endif
+       duk_push_uint(ctx, (duk_uint_t) line);
+
+       /* Providing access to e.g. act->lex_env would be dangerous: these
+        * internal structures must never be accessible to the application.
+        * Duktape relies on them having consistent data, and this consistency
+        * is only asserted for, not checked for.
+        */
+
+       /* [ level obj func pc line ] */
+
+       /* XXX: version specific array format instead? */
+       duk_xdef_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER);
+       duk_xdef_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC);
+       duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION);
+       return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
+#ifdef DUK_USE_MARK_AND_SWEEP
+       duk_hthread *thr = (duk_hthread *) ctx;
+       duk_small_uint_t flags;
+       duk_bool_t rc;
+
+       flags = (duk_small_uint_t) duk_get_uint(ctx, 0);
+       rc = duk_heap_mark_and_sweep(thr->heap, flags);
+
+       /* XXX: Not sure what the best return value would be in the API.
+        * Return a boolean for now.  Note that rc == 0 is success (true).
+        */
+       duk_push_boolean(ctx, !rc);
+       return 1;
+#else
+       DUK_UNREF(ctx);
+       return 0;
+#endif
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
+       (void) duk_require_hobject(ctx, 0);
+       if (duk_get_top(ctx) >= 2) {
+               /* Set: currently a finalizer is disabled by setting it to
+                * undefined; this does not remove the property at the moment.
+                * The value could be type checked to be either a function
+                * or something else; if something else, the property could
+                * be deleted.
+                */
+               duk_set_top(ctx, 2);
+               (void) duk_put_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
+               return 0;
+       } else {
+               /* Get. */
+               DUK_ASSERT(duk_get_top(ctx) == 1);
+               duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
+               return 1;
+       }
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
+       duk_hthread *thr = (duk_hthread *) ctx;
+       duk_hstring *h_str;
+
+       DUK_UNREF(thr);
+
+       /* Vararg function: must be careful to check/require arguments.
+        * The JSON helpers accept invalid indices and treat them like
+        * non-existent optional parameters.
+        */
+
+       h_str = duk_require_hstring(ctx, 0);
+       duk_require_valid_index(ctx, 1);
+
+       if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
+               duk_set_top(ctx, 2);
+               duk_hex_encode(ctx, 1);
+               DUK_ASSERT_TOP(ctx, 2);
+       } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
+               duk_set_top(ctx, 2);
+               duk_base64_encode(ctx, 1);
+               DUK_ASSERT_TOP(ctx, 2);
+#ifdef DUK_USE_JX
+       } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
+               duk_bi_json_stringify_helper(ctx,
+                                            1 /*idx_value*/,
+                                            2 /*idx_replacer*/,
+                                            3 /*idx_space*/,
+                                            DUK_JSON_FLAG_EXT_CUSTOM |
+                                            DUK_JSON_FLAG_ASCII_ONLY |
+                                            DUK_JSON_FLAG_AVOID_KEY_QUOTES 
/*flags*/);
+#endif
+#ifdef DUK_USE_JC
+       } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
+               duk_bi_json_stringify_helper(ctx,
+                                            1 /*idx_value*/,
+                                            2 /*idx_replacer*/,
+                                            3 /*idx_space*/,
+                                            DUK_JSON_FLAG_EXT_COMPATIBLE |
+                                            DUK_JSON_FLAG_ASCII_ONLY 
/*flags*/);
+#endif
+       } else {
+               return DUK_RET_TYPE_ERROR;
+       }
+       return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
+       duk_hthread *thr = (duk_hthread *) ctx;
+       duk_hstring *h_str;
+
+       DUK_UNREF(thr);
+
+       /* Vararg function: must be careful to check/require arguments.
+        * The JSON helpers accept invalid indices and treat them like
+        * non-existent optional parameters.
+        */
+
+       h_str = duk_require_hstring(ctx, 0);
+       duk_require_valid_index(ctx, 1);
+
+       if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
+               duk_set_top(ctx, 2);
+               duk_hex_decode(ctx, 1);
+               DUK_ASSERT_TOP(ctx, 2);
+       } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
+               duk_set_top(ctx, 2);
+               duk_base64_decode(ctx, 1);
+               DUK_ASSERT_TOP(ctx, 2);
+#ifdef DUK_USE_JX
+       } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
+               duk_bi_json_parse_helper(ctx,
+                                        1 /*idx_value*/,
+                                        2 /*idx_replacer*/,
+                                        DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
+#endif
+#ifdef DUK_USE_JC
+       } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
+               duk_bi_json_parse_helper(ctx,
+                                        1 /*idx_value*/,
+                                        2 /*idx_replacer*/,
+                                        DUK_JSON_FLAG_EXT_COMPATIBLE 
/*flags*/);
+#endif
+       } else {
+               return DUK_RET_TYPE_ERROR;
+       }
+       return 1;
+}
+
+/*
+ *  Compact an object
+ */
+
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
+       DUK_ASSERT_TOP(ctx, 1);
+       duk_compact(ctx, 0);
+       return 1;  /* return the argument object */
+}

Reply via email to