diff --git a/Makefile b/Makefile index 0e08a2fef..0057eeac8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ RELEASE=5.4 PACKAGE=ceph -VER=12.2.12 +VER=12.2.13 DEBREL=pve1 SRCDIR=ceph diff --git a/ceph/CMakeLists.txt b/ceph/CMakeLists.txt index bffe5649b..832e19f01 100644 --- a/ceph/CMakeLists.txt +++ b/ceph/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8.11) project(ceph) -set(VERSION 12.2.12) +set(VERSION 12.2.13) if(POLICY CMP0046) # Tweak policies (this one disables "missing" dependency warning) diff --git a/ceph/PendingReleaseNotes b/ceph/PendingReleaseNotes index 03daee301..d9de28082 100644 --- a/ceph/PendingReleaseNotes +++ b/ceph/PendingReleaseNotes @@ -1,3 +1,48 @@ +12.2.13 +------- +* Ceph now packages python bindings for python3.6 instead of + python3.4, because EPEL7 recently switched from python3.4 to + python3.6 as the native python3. see the `announcement _` + for more details on the background of this change. + +* We now have telemetry support via a ceph-mgr module. The telemetry module is + absolutely on an opt-in basis, and is meant to collect generic cluster + information and push it to a central endpoint. By default, we're pushing it + to a project endpoint at https://telemetry.ceph.com/report, but this is + customizable using by setting the 'url' config option with:: + + ceph telemetry config-set url '' + + You will have to opt-in on sharing your information with:: + + ceph telemetry on + + You can view exactly what information will be reported first with:: + + ceph telemetry show + + Should you opt-in, your information will be licensed under the + Community Data License Agreement - Sharing - Version 1.0, which you can + read at https://cdla.io/sharing-1-0/ + + The telemetry module reports information about CephFS file systems, + including: + + - how many MDS daemons (in total and per file system) + - which features are (or have been) enabled + - how many data pools + - approximate file system age (year + month of creation) + - how much metadata is being cached per file system + + As well as: + + - whether IPv4 or IPv6 addresses are used for the monitors + - whether RADOS cache tiering is enabled (and which mode) + - whether pools are replicated or erasure coded, and + which erasure code profile plugin and parameters are in use + - how many RGW daemons, zones, and zonegroups are present; which RGW frontends are in use + - aggregate stats about the CRUSH map, like which algorithms are used, how big buckets are, how many rules are defined, and what tunables are in use + 12.2.12 ------- * In 12.2.9 and earlier releases, keyring caps were not checked for validity, @@ -182,3 +227,29 @@ 'ceph osd set pglog_hardlimit' after completely upgrading to 12.2.11. Once all the OSDs have this flag set, the length of the pg log will be capped by a hard limit. We do not recommend unsetting this flag beyond this point. + +* A health warning is now generated if the average osd heartbeat ping + time exceeds a configurable threshold for any of the intervals + computed. The OSD computes 1 minute, 5 minute and 15 minute + intervals with average, minimum and maximum values. New configuration + option ``mon_warn_on_slow_ping_ratio`` specifies a percentage of + ``osd_heartbeat_grace`` to determine the threshold. A value of zero + disables the warning. New configuration option + ``mon_warn_on_slow_ping_time`` specified in milliseconds over-rides the + computed value, causes a warning + when OSD heartbeat pings take longer than the specified amount. + New admin command ``ceph daemon mgr.# dump_osd_network [threshold]`` command will + list all connections with a ping time longer than the specified threshold or + value determined by the config options, for the average for any of the 3 intervals. + New admin command ``ceph daemon osd.# dump_osd_network [threshold]`` will + do the same but only including heartbeats initiated by the specified OSD. + +* The configuration value ``osd_calc_pg_upmaps_max_stddev`` used for upmap + balancing has been removed. Instead use the mgr balancer config + ``upmap_max_deviation`` which now is an integer number of PGs of deviation + from the target PGs per OSD. This can be set with a command like + ``ceph config set mgr mgr/balancer/upmap_max_deviation 2``. The default + ``upmap_max_deviation`` is 1. There are situations where crush rules + would not allow a pool to ever have completely balanced PGs. For example, if + crush requires 1 replica on each of 3 racks, but there are fewer OSDs in 1 of + the racks. In those cases, the configuration value can be increased. diff --git a/ceph/admin/build-doc b/ceph/admin/build-doc index 0caa04876..22e47a02e 100755 --- a/ceph/admin/build-doc +++ b/ceph/admin/build-doc @@ -20,8 +20,8 @@ if command -v dpkg >/dev/null; then exit 1 fi elif command -v yum >/dev/null; then - for package in python-devel python-pip python-virtualenv doxygen ditaa ant libxml2-devel libxslt-devel Cython graphviz; do - if ! rpm -q $package >/dev/null ; then + for package in python36-devel python36-pip python36-virtualenv doxygen ditaa ant libxml2-devel libxslt-devel python36-Cython graphviz; do + if ! rpm -q --whatprovides $package >/dev/null ; then missing="${missing:+$missing }$package" fi done @@ -57,7 +57,7 @@ cd build-doc [ -z "$vdir" ] && vdir="$TOPDIR/build-doc/virtualenv" if [ ! -e $vdir ]; then - virtualenv --system-site-packages $vdir -p python2 + virtualenv --python=python3 --system-site-packages $vdir fi $vdir/bin/pip install --quiet -r $TOPDIR/admin/doc-requirements.txt diff --git a/ceph/admin/doc-requirements.txt b/ceph/admin/doc-requirements.txt index 44920d4bc..0af3bde92 100644 --- a/ceph/admin/doc-requirements.txt +++ b/ceph/admin/doc-requirements.txt @@ -1,3 +1,4 @@ -Sphinx == 1.6.3 --e git+https://github.com/ceph/sphinx-ditaa.git@py3#egg=sphinx-ditaa -breathe == 4.11.1 +Sphinx == 2.1.2 +git+https://github.com/ceph/sphinx-ditaa.git@py3#egg=sphinx-ditaa +breathe == 4.13.1 +pyyaml >= 5.1.2 diff --git a/ceph/alpine/APKBUILD b/ceph/alpine/APKBUILD index f29f0428b..50b8e2c40 100644 --- a/ceph/alpine/APKBUILD +++ b/ceph/alpine/APKBUILD @@ -1,7 +1,7 @@ # Contributor: John Coyle # Maintainer: John Coyle pkgname=ceph -pkgver=12.2.12 +pkgver=12.2.13 pkgrel=0 pkgdesc="Ceph is a distributed object store and file system" pkgusers="ceph" @@ -63,7 +63,7 @@ makedepends=" xmlstarlet yasm " -source="ceph-12.2.12.tar.bz2" +source="ceph-12.2.13.tar.bz2" subpackages=" $pkgname-base $pkgname-common @@ -116,7 +116,7 @@ _sysconfdir=/etc _udevrulesdir=/etc/udev/rules.d _python_sitelib=/usr/lib/python2.7/site-packages -builddir=$srcdir/ceph-12.2.12 +builddir=$srcdir/ceph-12.2.13 build() { export CEPH_BUILD_VIRTUALENV=$builddir diff --git a/ceph/ceph.spec b/ceph/ceph.spec index 9c42008a1..d44c18d40 100644 --- a/ceph/ceph.spec +++ b/ceph/ceph.spec @@ -15,30 +15,27 @@ # Please submit bugfixes or comments via http://tracker.ceph.com/ # %bcond_without ocf -%bcond_without cephfs_java -%if 0%{?suse_version} -%bcond_with ceph_test_package -%else -%bcond_without ceph_test_package -%endif %bcond_with make_check +%bcond_without ceph_test_package %ifarch s390 s390x %bcond_with tcmalloc %else %bcond_without tcmalloc %endif -%bcond_with lowmem_builder %if 0%{?fedora} || 0%{?rhel} %bcond_without selinux +%bcond_without cephfs_java +%bcond_with lowmem_builder +%bcond_without lttng %endif %if 0%{?suse_version} %bcond_with selinux -%endif - -# LTTng-UST enabled on Fedora, RHEL 6+, and SLE (not openSUSE) -%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?suse_version} -%if ! 0%{?is_opensuse} +%bcond_with cephfs_java +%bcond_without lowmem_builder +%ifarch x86_64 aarch64 %bcond_without lttng +%else +%bcond_with lttng %endif %endif @@ -50,7 +47,8 @@ %{!?_udevrulesdir: %global _udevrulesdir /lib/udev/rules.d} %{!?tmpfiles_create: %global tmpfiles_create systemd-tmpfiles --create} %{!?python3_pkgversion: %global python3_pkgversion 3} - +%{!?python3_version_nodots: %global python3_version_nodots 3} +%{!?python3_version: %global python3_version 3} # unify libexec for all targets %global _libexecdir %{_exec_prefix}/lib @@ -61,7 +59,7 @@ # main package definition ################################################################################# Name: ceph -Version: 12.2.12 +Version: 12.2.13 Release: 0%{?dist} %if 0%{?fedora} || 0%{?rhel} Epoch: 2 @@ -77,7 +75,7 @@ License: LGPL-2.1 and CC-BY-SA-3.0 and GPL-2.0 and BSL-1.0 and BSD-3-Clause and Group: System/Filesystems %endif URL: http://ceph.com/ -Source0: http://ceph.com/download/ceph-12.2.12.tar.bz2 +Source0: http://ceph.com/download/ceph-12.2.13.tar.bz2 %if 0%{?suse_version} %if 0%{?is_opensuse} ExclusiveArch: x86_64 aarch64 ppc64 ppc64le @@ -113,6 +111,7 @@ BuildRequires: python-numpy-devel %endif BuildRequires: python-coverage BuildRequires: python-pecan +BuildRequires: python-tox BuildRequires: socat %endif BuildRequires: bc @@ -196,9 +195,9 @@ BuildRequires: python-sphinx %endif # python34-... for RHEL, python3-... for all other supported distros %if 0%{?rhel} -BuildRequires: python34-devel -BuildRequires: python34-setuptools -BuildRequires: python34-Cython +BuildRequires: python%{python3_pkgversion}-devel +BuildRequires: python%{python3_pkgversion}-setuptools +BuildRequires: python%{python3_version_nodots}-Cython %else BuildRequires: python3-devel BuildRequires: python3-setuptools @@ -501,6 +500,7 @@ Group: Development/Languages/Python %endif Requires: librgw2 = %{_epoch_prefix}%{version}-%{release} Requires: python-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python-rgw} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} %description -n python-rgw This package contains Python 2 libraries for interacting with Cephs RADOS @@ -513,6 +513,7 @@ Group: Development/Languages/Python %endif Requires: librgw2 = %{_epoch_prefix}%{version}-%{release} Requires: python%{python3_pkgversion}-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python%{python3_pkgversion}-rgw} %description -n python%{python3_pkgversion}-rgw This package contains Python 3 libraries for interacting with Cephs RADOS gateway. @@ -523,6 +524,7 @@ Summary: Python 2 libraries for the RADOS object store Group: Development/Languages/Python %endif Requires: librados2 = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python-rados} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} %description -n python-rados This package contains Python 2 libraries for interacting with Cephs RADOS @@ -535,6 +537,7 @@ Group: Development/Languages/Python %endif Requires: python%{python3_pkgversion} Requires: librados2 = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python%{python3_pkgversion}-rados} %description -n python%{python3_pkgversion}-rados This package contains Python 3 libraries for interacting with Cephs RADOS object store. @@ -603,6 +606,7 @@ Group: Development/Languages/Python %endif Requires: librbd1 = %{_epoch_prefix}%{version}-%{release} Requires: python-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python-rbd} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} %description -n python-rbd This package contains Python 2 libraries for interacting with Cephs RADOS @@ -615,6 +619,7 @@ Group: Development/Languages/Python %endif Requires: librbd1 = %{_epoch_prefix}%{version}-%{release} Requires: python%{python3_pkgversion}-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python%{python3_pkgversion}-rbd} %description -n python%{python3_pkgversion}-rbd This package contains Python 3 libraries for interacting with Cephs RADOS block device. @@ -655,9 +660,8 @@ Summary: Python 2 libraries for Ceph distributed file system Group: Development/Languages/Python %endif Requires: libcephfs2 = %{_epoch_prefix}%{version}-%{release} -%if 0%{?suse_version} -Recommends: python-rados = %{_epoch_prefix}%{version}-%{release} -%endif +Requires: python-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python-cephfs} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} %description -n python-cephfs This package contains Python 2 libraries for interacting with Cephs distributed @@ -670,6 +674,7 @@ Group: Development/Languages/Python %endif Requires: libcephfs2 = %{_epoch_prefix}%{version}-%{release} Requires: python%{python3_pkgversion}-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python%{python3_pkgversion}-cephfs} %description -n python%{python3_pkgversion}-cephfs This package contains Python 3 libraries for interacting with Cephs distributed file system. @@ -679,6 +684,7 @@ Summary: Python 3 utility libraries for Ceph CLI %if 0%{?suse_version} Group: Development/Languages/Python %endif +%{?python_provide:%python_provide python%{python3_pkgversion}-ceph-argparse} %description -n python%{python3_pkgversion}-ceph-argparse This package contains types and routines for Python 3 used by the Ceph CLI as well as the RESTful interface. These have to do with querying the daemons for @@ -788,7 +794,7 @@ python-rbd, python-rgw or python-cephfs instead. # common ################################################################################# %prep -%autosetup -p1 -n ceph-12.2.12 +%autosetup -p1 -n ceph-12.2.13 %build %if 0%{with cephfs_java} @@ -833,7 +839,7 @@ cmake .. \ -DCMAKE_INSTALL_DOCDIR=%{_docdir}/ceph \ -DCMAKE_INSTALL_INCLUDEDIR=%{_includedir} \ -DWITH_MANPAGE=ON \ - -DWITH_PYTHON3=ON \ + -DWITH_PYTHON3=%{python3_version} \ -DWITH_SYSTEMD=ON \ %if 0%{?rhel} && ! 0%{?centos} -DWITH_SUBMAN=ON \ diff --git a/ceph/ceph.spec.in b/ceph/ceph.spec.in index aa3c47abe..662177479 100644 --- a/ceph/ceph.spec.in +++ b/ceph/ceph.spec.in @@ -15,30 +15,27 @@ # Please submit bugfixes or comments via http://tracker.ceph.com/ # %bcond_without ocf -%bcond_without cephfs_java -%if 0%{?suse_version} -%bcond_with ceph_test_package -%else -%bcond_without ceph_test_package -%endif %bcond_with make_check +%bcond_without ceph_test_package %ifarch s390 s390x %bcond_with tcmalloc %else %bcond_without tcmalloc %endif -%bcond_with lowmem_builder %if 0%{?fedora} || 0%{?rhel} %bcond_without selinux +%bcond_without cephfs_java +%bcond_with lowmem_builder +%bcond_without lttng %endif %if 0%{?suse_version} %bcond_with selinux -%endif - -# LTTng-UST enabled on Fedora, RHEL 6+, and SLE (not openSUSE) -%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?suse_version} -%if ! 0%{?is_opensuse} +%bcond_with cephfs_java +%bcond_without lowmem_builder +%ifarch x86_64 aarch64 %bcond_without lttng +%else +%bcond_with lttng %endif %endif @@ -50,7 +47,8 @@ %{!?_udevrulesdir: %global _udevrulesdir /lib/udev/rules.d} %{!?tmpfiles_create: %global tmpfiles_create systemd-tmpfiles --create} %{!?python3_pkgversion: %global python3_pkgversion 3} - +%{!?python3_version_nodots: %global python3_version_nodots 3} +%{!?python3_version: %global python3_version 3} # unify libexec for all targets %global _libexecdir %{_exec_prefix}/lib @@ -113,6 +111,7 @@ BuildRequires: python-numpy-devel %endif BuildRequires: python-coverage BuildRequires: python-pecan +BuildRequires: python-tox BuildRequires: socat %endif BuildRequires: bc @@ -196,9 +195,9 @@ BuildRequires: python-sphinx %endif # python34-... for RHEL, python3-... for all other supported distros %if 0%{?rhel} -BuildRequires: python34-devel -BuildRequires: python34-setuptools -BuildRequires: python34-Cython +BuildRequires: python%{python3_pkgversion}-devel +BuildRequires: python%{python3_pkgversion}-setuptools +BuildRequires: python%{python3_version_nodots}-Cython %else BuildRequires: python3-devel BuildRequires: python3-setuptools @@ -501,6 +500,7 @@ Group: Development/Languages/Python %endif Requires: librgw2 = %{_epoch_prefix}%{version}-%{release} Requires: python-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python-rgw} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} %description -n python-rgw This package contains Python 2 libraries for interacting with Cephs RADOS @@ -513,6 +513,7 @@ Group: Development/Languages/Python %endif Requires: librgw2 = %{_epoch_prefix}%{version}-%{release} Requires: python%{python3_pkgversion}-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python%{python3_pkgversion}-rgw} %description -n python%{python3_pkgversion}-rgw This package contains Python 3 libraries for interacting with Cephs RADOS gateway. @@ -523,6 +524,7 @@ Summary: Python 2 libraries for the RADOS object store Group: Development/Languages/Python %endif Requires: librados2 = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python-rados} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} %description -n python-rados This package contains Python 2 libraries for interacting with Cephs RADOS @@ -535,6 +537,7 @@ Group: Development/Languages/Python %endif Requires: python%{python3_pkgversion} Requires: librados2 = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python%{python3_pkgversion}-rados} %description -n python%{python3_pkgversion}-rados This package contains Python 3 libraries for interacting with Cephs RADOS object store. @@ -603,6 +606,7 @@ Group: Development/Languages/Python %endif Requires: librbd1 = %{_epoch_prefix}%{version}-%{release} Requires: python-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python-rbd} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} %description -n python-rbd This package contains Python 2 libraries for interacting with Cephs RADOS @@ -615,6 +619,7 @@ Group: Development/Languages/Python %endif Requires: librbd1 = %{_epoch_prefix}%{version}-%{release} Requires: python%{python3_pkgversion}-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python%{python3_pkgversion}-rbd} %description -n python%{python3_pkgversion}-rbd This package contains Python 3 libraries for interacting with Cephs RADOS block device. @@ -655,9 +660,8 @@ Summary: Python 2 libraries for Ceph distributed file system Group: Development/Languages/Python %endif Requires: libcephfs2 = %{_epoch_prefix}%{version}-%{release} -%if 0%{?suse_version} -Recommends: python-rados = %{_epoch_prefix}%{version}-%{release} -%endif +Requires: python-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python-cephfs} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} %description -n python-cephfs This package contains Python 2 libraries for interacting with Cephs distributed @@ -670,6 +674,7 @@ Group: Development/Languages/Python %endif Requires: libcephfs2 = %{_epoch_prefix}%{version}-%{release} Requires: python%{python3_pkgversion}-rados = %{_epoch_prefix}%{version}-%{release} +%{?python_provide:%python_provide python%{python3_pkgversion}-cephfs} %description -n python%{python3_pkgversion}-cephfs This package contains Python 3 libraries for interacting with Cephs distributed file system. @@ -679,6 +684,7 @@ Summary: Python 3 utility libraries for Ceph CLI %if 0%{?suse_version} Group: Development/Languages/Python %endif +%{?python_provide:%python_provide python%{python3_pkgversion}-ceph-argparse} %description -n python%{python3_pkgversion}-ceph-argparse This package contains types and routines for Python 3 used by the Ceph CLI as well as the RESTful interface. These have to do with querying the daemons for @@ -833,7 +839,7 @@ cmake .. \ -DCMAKE_INSTALL_DOCDIR=%{_docdir}/ceph \ -DCMAKE_INSTALL_INCLUDEDIR=%{_includedir} \ -DWITH_MANPAGE=ON \ - -DWITH_PYTHON3=ON \ + -DWITH_PYTHON3=%{python3_version} \ -DWITH_SYSTEMD=ON \ %if 0%{?rhel} && ! 0%{?centos} -DWITH_SUBMAN=ON \ diff --git a/ceph/changelog.upstream b/ceph/changelog.upstream index 3f8f429e8..a668f42f6 100644 --- a/ceph/changelog.upstream +++ b/ceph/changelog.upstream @@ -1,3 +1,9 @@ +ceph (12.2.13-1) stable; urgency=medium + + * New upstream release + + -- Ceph Release Team Thu, 30 Jan 2020 20:52:35 +0000 + ceph (12.2.12-1) stable; urgency=medium * New upstream release diff --git a/ceph/cmake/modules/SIMDExt.cmake b/ceph/cmake/modules/SIMDExt.cmake index 5330835aa..90534386e 100644 --- a/ceph/cmake/modules/SIMDExt.cmake +++ b/ceph/cmake/modules/SIMDExt.cmake @@ -16,49 +16,21 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64") set(HAVE_ARM 1) - set(save_quiet ${CMAKE_REQUIRED_QUIET}) - set(CMAKE_REQUIRED_QUIET true) - include(CheckCXXSourceCompiles) - - check_cxx_source_compiles(" - #define CRC32CX(crc, value) __asm__(\"crc32cx %w[c], %w[c], %x[v]\":[c]\"+r\"(crc):[v]\"r\"(value)) - asm(\".arch_extension crc\"); - unsigned int foo(unsigned int ret) { - CRC32CX(ret, 0); - return ret; - } - int main() { foo(0); }" HAVE_ARMV8_CRC) - check_cxx_source_compiles(" - asm(\".arch_extension crypto\"); - unsigned int foo(unsigned int ret) { - __asm__(\"pmull v2.1q, v2.1d, v1.1d\"); - return ret; - } - int main() { foo(0); }" HAVE_ARMV8_CRYPTO) - - set(CMAKE_REQUIRED_QUIET ${save_quiet}) - if(HAVE_ARMV8_CRC) - message(STATUS " aarch64 crc extensions supported") - endif() - - if(HAVE_ARMV8_CRYPTO) - message(STATUS " aarch64 crypto extensions supported") - endif() - CHECK_C_COMPILER_FLAG(-march=armv8-a+crc+crypto HAVE_ARMV8_CRC_CRYPTO_MARCH) - - # don't believe only the -march support; gcc 4.8.5 on RHEL/CentOS says - # it supports +crc but hasn't got the intrinsics or arm_acle.h. Test for - # the actual presence of one of the intrinsic functions. - if(HAVE_ARMV8_CRC_CRYPTO_MARCH) - check_cxx_source_compiles(" - #include - int main() { uint32_t a; uint8_t b; __builtin_aarch64_crc32b(a, b); } - " HAVE_ARMV8_CRC_CRYPTO_INTRINSICS) - endif() + include(CheckCCompilerFlag) + check_c_compiler_flag(-march=armv8-a+crc+crypto HAVE_ARMV8_CRC_CRYPTO_INTRINSICS) if(HAVE_ARMV8_CRC_CRYPTO_INTRINSICS) - message(STATUS " aarch64 crc+crypto intrinsics supported") - set(ARMV8_CRC_COMPILE_FLAGS "${ARMV8_CRC_COMPILE_FLAGS} -march=armv8-a+crc+crypto") + set(ARMV8_CRC_COMPILE_FLAGS "-march=armv8-a+crc+crypto") + set(HAVE_ARMV8_CRC TRUE) + set(HAVE_ARMV8_CRYPTO TRUE) + else() + check_c_compiler_flag(-march=armv8-a+crc HAVE_ARMV8_CRC) + check_c_compiler_flag(-march=armv8-a+crypto HAVE_ARMV8_CRYPTO) + if(HAVE_ARMV8_CRC) + set(ARMV8_CRC_COMPILE_FLAGS "-march=armv8-a+crc") + elseif(HAVE_ARMV8_CRYPTO) + set(ARMV8_CRC_COMPILE_FLAGS "-march=armv8-a+crypto") + endif() endif() CHECK_C_COMPILER_FLAG(-march=armv8-a+simd HAVE_ARMV8_SIMD) diff --git a/ceph/debian/control b/ceph/debian/control index 65c29ed0d..212e64967 100644 --- a/ceph/debian/control +++ b/ceph/debian/control @@ -886,6 +886,7 @@ Package: python-rgw Architecture: linux-any Section: python Depends: librgw2 (>= ${binary:Version}), + python-rados (= ${binary:Version}), ${misc:Depends}, ${python:Depends}, ${shlibs:Depends}, @@ -920,6 +921,7 @@ Package: python3-rgw Architecture: linux-any Section: python Depends: librgw2 (>= ${binary:Version}), + python3-rados (= ${binary:Version}), ${misc:Depends}, ${python3:Depends}, ${shlibs:Depends}, @@ -952,6 +954,7 @@ Package: python-cephfs Architecture: linux-any Section: python Depends: libcephfs2 (= ${binary:Version}), + python-rados (= ${binary:Version}), ${misc:Depends}, ${python:Depends}, ${shlibs:Depends}, @@ -986,6 +989,7 @@ Package: python3-cephfs Architecture: linux-any Section: python Depends: libcephfs2 (= ${binary:Version}), + python3-rados (= ${binary:Version}), ${misc:Depends}, ${python3:Depends}, ${shlibs:Depends}, diff --git a/ceph/do_cmake.sh b/ceph/do_cmake.sh index 739da8e5b..df1197de5 100755 --- a/ceph/do_cmake.sh +++ b/ceph/do_cmake.sh @@ -1,4 +1,5 @@ -#!/bin/sh -x +#!/usr/bin/env bash +set -x git submodule update --init --recursive if test -e build; then echo 'build dir already exists; rm -rf build and re-run' diff --git a/ceph/doc/dev/placement-group.rst b/ceph/doc/dev/placement-group.rst index 3c067ea3f..368039274 100644 --- a/ceph/doc/dev/placement-group.rst +++ b/ceph/doc/dev/placement-group.rst @@ -97,8 +97,11 @@ User-visible PG States *down* a replica with necessary data is down, so the pg is offline -*replay* - the PG is waiting for clients to replay operations after an OSD crashed +*recovery_unfound* + recovery could not finish because object(s) are unfound. + +*backfill_unfound* + backfill could not finish because object(s) are unfound. *splitting* the PG is being split into multiple PGs (not functional as of 2012-02) @@ -123,20 +126,9 @@ User-visible PG States *recovering* objects are being migrated/synchronized with replicas -*recovery_wait* - the PG is waiting for the local/remote recovery reservations - -*backfilling* - a special case of recovery, in which the entire contents of - the PG are scanned and synchronized, instead of inferring what - needs to be transferred from the PG logs of recent operations - *backfill_wait* the PG is waiting in line to start backfill -*backfill_toofull* - backfill reservation rejected, OSD too full - *incomplete* a pg is missing a necessary period of history from its log. If you see this state, report a bug, and try to start any @@ -149,3 +141,64 @@ User-visible PG States *remapped* the PG is temporarily mapped to a different set of OSDs from what CRUSH specified + +*deep* + In conjunction with *scrubbing* the scrub is a deep scrub + +*backfilling* + a special case of recovery, in which the entire contents of + the PG are scanned and synchronized, instead of inferring what + needs to be transferred from the PG logs of recent operations + +*backfill_toofull* + backfill reservation rejected, OSD too full + +*recovery_wait* + the PG is waiting for the local/remote recovery reservations + +*undersized* + the PG can't select enough OSDs given its size + +*activating* + the PG is peered but not yet active + +*peered* + the PG peered but can't go active + +*snaptrim* + the PG is trimming snaps + +*snaptrim_wait* + the PG is queued to trim snaps + +*recovery_toofull* + recovery reservation rejected, OSD too full + +*snaptrim_error* + the PG could not complete snap trimming due to errors + +*forced_recovery* + the PG has been marked for highest priority recovery + +*forced_backfill* + the PG has been marked for highest priority backfill + +======= +OMAP STATISTICS +=============== + +Omap statistics are gathered during deep scrub and displayed in the output of +the following commands:: + + ceph pg dump + ceph pg dump all + ceph pg dump summary + ceph pg dump pgs + ceph pg dump pools + ceph pg ls + +As these statistics are not updated continuously they may be quite inaccurate in +an environment where deep scrubs are run infrequently and/or there is a lot of +omap activity. As such they should not be relied on for exact accuracy but +rather used as a guide. Running a deep scrub and checking these statistics +immediately afterwards should give a good indication of current omap usage. diff --git a/ceph/doc/man/8/ceph-bluestore-tool.rst b/ceph/doc/man/8/ceph-bluestore-tool.rst index f5e5fe2b8..0742f7d92 100644 --- a/ceph/doc/man/8/ceph-bluestore-tool.rst +++ b/ceph/doc/man/8/ceph-bluestore-tool.rst @@ -19,7 +19,7 @@ Synopsis | **ceph-bluestore-tool** show-label --dev *device* ... | **ceph-bluestore-tool** prime-osd-dir --dev *device* --path *osd path* | **ceph-bluestore-tool** bluefs-export --path *osd path* --out-dir *dir* -| **ceph-bluestore-tool** bluefs-export --path *osd path* --out-dir *dir* +| **ceph-bluestore-tool** free-dump|free-score --path *osd path* [ --allocator block/bluefs-wal/bluefs-db/bluefs-slow ] Description @@ -59,6 +59,15 @@ Commands Show device label(s). +:command:`free-dump` --path *osd path* [ --allocator block/bluefs-wal/bluefs-db/bluefs-slow ] + + Dump all free regions in allocator. + +:command:`free-score` --path *osd path* [ --allocator block/bluefs-wal/bluefs-db/bluefs-slow ] + + Give a [0-1] number that represents quality of fragmentation in allocator. + 0 represents case when all free space is in one chunk. 1 represents worst possible fragmentation. + Options ======= @@ -87,6 +96,10 @@ Options deep scrub/repair (read and validate object data, not just metadata) +.. option:: --allocator *name* + + Useful for *free-dump* and *free-score* actions. Selects allocator(s). + Device labels ============= diff --git a/ceph/doc/man/8/osdmaptool.rst b/ceph/doc/man/8/osdmaptool.rst index f58d29cdd..d5c0c7788 100644 --- a/ceph/doc/man/8/osdmaptool.rst +++ b/ceph/doc/man/8/osdmaptool.rst @@ -11,6 +11,12 @@ Synopsis | **osdmaptool** *mapfilename* [--print] [--createsimple *numosd* [--pgbits *bitsperosd* ] ] [--clobber] +| **osdmaptool** *mapfilename* [--import-crush *crushmap*] +| **osdmaptool** *mapfilename* [--export-crush *crushmap*] +| **osdmaptool** *mapfilename* [--upmap *file*] [--upmap-max *max-optimizations*] + [--upmap-deviation *max-deviation*] [--upmap-pool *poolname*] + [--upmap-save *file*] [--upmap-save *newosdmap*] [--upmap-active] +| **osdmaptool** *mapfilename* [--upmap-cleanup] [--upmap-save *newosdmap*] Description @@ -19,6 +25,8 @@ Description **osdmaptool** is a utility that lets you create, view, and manipulate OSD cluster maps from the Ceph distributed storage system. Notably, it lets you extract the embedded CRUSH map or import a new CRUSH map. +It can also simulate the upmap balancer mode so you can get a sense of +what is needed to balance your PGs. Options @@ -58,6 +66,46 @@ Options will print out the summary of all placement groups and the mappings from them to the mapped OSDs. +.. option:: --mark-out + + mark an osd as out (but do not persist) + +.. option:: --health + + dump health checks + +.. option:: --with-default-pool + + include default pool when creating map + +.. option:: --upmap-cleanup + + clean up pg_upmap[_items] entries, writing commands to [default: - for stdout] + +.. option:: --upmap + + calculate pg upmap entries to balance pg layout writing commands to [default: - for stdout] + +.. option:: --upmap-max + + set max upmap entries to calculate [default: 10] + +.. option:: --upmap-deviation + + max deviation from target [default: 5] + +.. option:: --upmap-pool + + restrict upmap balancing to 1 pool or the option can be repeated for multiple pools + +.. option:: --upmap-save + + write modified OSDMap with upmap changes + +.. option:: --upmap-active + + Act like an active balancer, keep applying changes until balanced + Example ======= @@ -70,19 +118,19 @@ To view the result:: osdmaptool --print osdmap -To view the mappings of placement groups for pool 0:: +To view the mappings of placement groups for pool 1:: - osdmaptool --test-map-pgs-dump rbd --pool 0 + osdmaptool osdmap --test-map-pgs-dump --pool 1 pool 0 pg_num 8 - 0.0 [0,2,1] 0 - 0.1 [2,0,1] 2 - 0.2 [0,1,2] 0 - 0.3 [2,0,1] 2 - 0.4 [0,2,1] 0 - 0.5 [0,2,1] 0 - 0.6 [0,1,2] 0 - 0.7 [1,0,2] 1 + 1.0 [0,2,1] 0 + 1.1 [2,0,1] 2 + 1.2 [0,1,2] 0 + 1.3 [2,0,1] 2 + 1.4 [0,2,1] 0 + 1.5 [0,2,1] 0 + 1.6 [0,1,2] 0 + 1.7 [1,0,2] 1 #osd count first primary c wt wt osd.0 8 5 5 1 1 osd.1 8 1 1 1 1 @@ -97,7 +145,7 @@ To view the mappings of placement groups for pool 0:: size 3 8 In which, - #. pool 0 has 8 placement groups. And two tables follow: + #. pool 1 has 8 placement groups. And two tables follow: #. A table for placement groups. Each row presents a placement group. With columns of: * placement group id, @@ -141,6 +189,56 @@ placement group distribution, whose standard deviation is 1.41421:: size 20 size 364 + To simulate the active balancer in upmap mode:: + + osdmaptool --upmap upmaps.out --upmap-active --upmap-deviation 6 --upmap-max 11 osdmap + + osdmaptool: osdmap file 'osdmap' + writing upmap command output to: upmaps.out + checking for upmap cleanups + upmap, max-count 11, max deviation 6 + pools movies photos metadata data + prepared 11/11 changes + Time elapsed 0.00310404 secs + pools movies photos metadata data + prepared 11/11 changes + Time elapsed 0.00283402 secs + pools data metadata movies photos + prepared 11/11 changes + Time elapsed 0.003122 secs + pools photos metadata data movies + prepared 11/11 changes + Time elapsed 0.00324372 secs + pools movies metadata data photos + prepared 1/11 changes + Time elapsed 0.00222609 secs + pools data movies photos metadata + prepared 0/11 changes + Time elapsed 0.00209916 secs + Unable to find further optimization, or distribution is already perfect + osd.0 pgs 41 + osd.1 pgs 42 + osd.2 pgs 42 + osd.3 pgs 41 + osd.4 pgs 46 + osd.5 pgs 39 + osd.6 pgs 39 + osd.7 pgs 43 + osd.8 pgs 41 + osd.9 pgs 46 + osd.10 pgs 46 + osd.11 pgs 46 + osd.12 pgs 46 + osd.13 pgs 41 + osd.14 pgs 40 + osd.15 pgs 40 + osd.16 pgs 39 + osd.17 pgs 46 + osd.18 pgs 46 + osd.19 pgs 39 + osd.20 pgs 42 + Total time elapsed 0.0167765 secs, 5 rounds + Availability ============ diff --git a/ceph/doc/man/8/rados.rst b/ceph/doc/man/8/rados.rst index 949010537..a353518b5 100644 --- a/ceph/doc/man/8/rados.rst +++ b/ceph/doc/man/8/rados.rst @@ -28,6 +28,12 @@ Options Interact with the given pool. Required by most commands. +.. option:: --pgid + + As an alternative to ``--pool``, ``--pgid`` also allow users to specify the + PG id to which the command will be directed. With this option, certain + commands like ``ls`` allow users to limit the scope of the command to the given PG. + .. option:: -s snap, --snap snap Read from the given pool snapshot. Valid for all pool-specific read operations. @@ -107,7 +113,7 @@ Pool specific commands List the watchers of object name. :command:`ls` *outfile* - List objects in given pool and write to outfile. + List objects in the given pool and write to outfile. Instead of ``--pool`` if ``--pgid`` will be specified, ``ls`` will only list the objects in the given PG. :command:`lssnap` List snapshots for given pool. @@ -189,6 +195,10 @@ To get a list object in pool foo sent to stdout:: rados -p foo ls - +To get a list of objects in PG 0.6:: + + rados --pgid 0.6 ls + To write an object:: rados -p foo put myobject blah.txt diff --git a/ceph/doc/man/8/radosgw-admin.rst b/ceph/doc/man/8/radosgw-admin.rst index e4ddb152e..2c4ac7e73 100644 --- a/ceph/doc/man/8/radosgw-admin.rst +++ b/ceph/doc/man/8/radosgw-admin.rst @@ -72,7 +72,10 @@ which are as follows: Remove access key. :command:`bucket list` - List all buckets. + List buckets, or, if bucket specified with --bucket=, + list its objects. If bucket specified adding --allow-unordered + removes ordering requirement, possibly generating results more + quickly in buckets with large number of objects. :command:`bucket link` Link bucket to specified user. @@ -226,6 +229,20 @@ which are as follows: :command:`orphans finish` Clean up search for leaked rados objects +:command:`reshard add` + Schedule a resharding of a bucket + +:command:`reshard list` + List all bucket resharding or scheduled to be resharded + +:command:`reshard process` + Process of scheduled reshard jobs + +:command:`reshard status` + Resharding status of a bucket + +:command:`reshard cancel` + Cancel resharding a bucket Options ======= diff --git a/ceph/doc/mgr/index.rst b/ceph/doc/mgr/index.rst index 30f951606..b827b921a 100644 --- a/ceph/doc/mgr/index.rst +++ b/ceph/doc/mgr/index.rst @@ -34,4 +34,5 @@ sensible. Zabbix plugin Prometheus plugin Influx plugin + Telemetry plugin diff --git a/ceph/doc/mgr/telemetry.rst b/ceph/doc/mgr/telemetry.rst new file mode 100644 index 000000000..8bb194bd7 --- /dev/null +++ b/ceph/doc/mgr/telemetry.rst @@ -0,0 +1,36 @@ +Telemetry plugin +================ +The telemetry plugin sends anonymous data about the cluster, in which it is running, back to the Ceph project. + +The data being sent back to the project does not contain any sensitive data like pool names, object names, object contents or hostnames. + +It contains counters and statistics on how the cluster has been deployed, the version of Ceph, the distribition of the hosts and other parameters which help the project to gain a better understanding of the way Ceph is used. + +Data is sent over HTTPS to *telemetry.ceph.com* + +Enabling +-------- + +The *telemetry* module is enabled with:: + + ceph mgr module enable telemetry + + +Interval +-------- +The module compiles and sends a new report every 72 hours by default. + +Contact and Description +----------------------- +A contact and description can be added to the report, this is optional. + + ceph telemetry config-set contact 'John Doe ' + ceph telemetry config-set description 'My first Ceph cluster' + +Show report +----------- +The report is sent in JSON format, and can be printed:: + + ceph telemetry show + +So you can inspect the content if you have privacy concerns. diff --git a/ceph/doc/rados/command/list-inconsistent-obj.json b/ceph/doc/rados/command/list-inconsistent-obj.json index 637e3ed8f..2bdc5f74c 100644 --- a/ceph/doc/rados/command/list-inconsistent-obj.json +++ b/ceph/doc/rados/command/list-inconsistent-obj.json @@ -91,7 +91,8 @@ "attr_value_mismatch", "attr_name_mismatch", "snapset_inconsistency", - "hinfo_inconsistency" + "hinfo_inconsistency", + "size_too_large" ] }, "minItems": 0, diff --git a/ceph/doc/rados/configuration/bluestore-config-ref.rst b/ceph/doc/rados/configuration/bluestore-config-ref.rst index d7e70ee92..507ca5b8c 100644 --- a/ceph/doc/rados/configuration/bluestore-config-ref.rst +++ b/ceph/doc/rados/configuration/bluestore-config-ref.rst @@ -231,12 +231,13 @@ The configured cache memory budget can be used in a few different ways: * BlueStore data (i.e., recently read or written object data) Cache memory usage is governed by the following options: -``bluestore_cache_meta_ratio``, ``bluestore_cache_kv_ratio``, and -``bluestore_cache_kv_max``. The fraction of the cache devoted to data -is 1.0 minus the meta and kv ratios. The memory devoted to kv -metadata (the RocksDB cache) is capped by ``bluestore_cache_kv_max`` -since our testing indicates there are diminishing returns beyond a -certain point. +``bluestore_cache_meta_ratio`` and ``bluestore_cache_kv_ratio``. +The fraction of the cache devoted to data +is governed by the effective bluestore cache size (depending on +``bluestore_cache_size[_ssd|_hdd]`` settings and the device class of the primary +device) as well as the meta and kv ratios. +The data fraction can be calculated by +`` * (1 - bluestore_cache_meta_ratio - bluestore_cache_kv_ratio)`` ``bluestore_cache_size`` @@ -264,14 +265,14 @@ certain point. :Description: The ratio of cache devoted to metadata. :Type: Floating point :Required: Yes -:Default: ``.01`` +:Default: ``.4`` ``bluestore_cache_kv_ratio`` :Description: The ratio of cache devoted to key/value data (rocksdb). :Type: Floating point :Required: Yes -:Default: ``.99`` +:Default: ``.4`` ``bluestore_cache_kv_max`` diff --git a/ceph/doc/rados/configuration/mon-config-ref.rst b/ceph/doc/rados/configuration/mon-config-ref.rst index 640e38203..992f1b674 100644 --- a/ceph/doc/rados/configuration/mon-config-ref.rst +++ b/ceph/doc/rados/configuration/mon-config-ref.rst @@ -395,6 +395,25 @@ by setting it in the ``[mon]`` section of the configuration file. :Default: True +``mon warn on slow ping ratio`` + +:Description: Issue a ``HEALTH_WARN`` in cluster log if any heartbeat + between OSDs exceeds ``mon warn on slow ping ratio`` + of ``osd heartbeat grace``. The default is 5%. +:Type: Float +:Default: ``0.05`` + + +``mon warn on slow ping time`` + +:Description: Override ``mon warn on slow ping ratio`` with a specific value. + Issue a ``HEALTH_WARN`` in cluster log if any heartbeat + between OSDs exceeds ``mon warn on slow ping time`` + milliseconds. The default is 0 (disabled). +:Type: Integer +:Default: ``0`` + + ``mon cache target full warn ratio`` :Description: Position between pool's ``cache_target_full`` and diff --git a/ceph/doc/rados/configuration/mon-osd-interaction.rst b/ceph/doc/rados/configuration/mon-osd-interaction.rst index e335ff070..c120187f2 100644 --- a/ceph/doc/rados/configuration/mon-osd-interaction.rst +++ b/ceph/doc/rados/configuration/mon-osd-interaction.rst @@ -24,10 +24,8 @@ monitoring the Ceph Storage Cluster. OSDs Check Heartbeats ===================== -Each Ceph OSD Daemon checks the heartbeat of other Ceph OSD Daemons every 6 -seconds. You can change the heartbeat interval by adding an ``osd heartbeat -interval`` setting under the ``[osd]`` section of your Ceph configuration file, -or by setting the value at runtime. If a neighboring Ceph OSD Daemon doesn't +Each Ceph OSD Daemon checks the heartbeat of other Ceph OSD Daemons at random +intervals less than every 6 seconds. If a neighboring Ceph OSD Daemon doesn't show a heartbeat within a 20 second grace period, the Ceph OSD Daemon may consider the neighboring Ceph OSD Daemon ``down`` and report it back to a Ceph Monitor, which will update the Ceph Cluster Map. You may change this grace @@ -379,6 +377,15 @@ OSD Settings :Default: ``30`` +``osd mon heartbeat stat stale`` + +:Description: Stop reporting on heartbeat ping times which haven't been updated for + this many seconds. Set to zero to disable this action. + +:Type: 32-bit Integer +:Default: ``3600`` + + ``osd mon report interval max`` :Description: The maximum time in seconds that a Ceph OSD Daemon can wait before diff --git a/ceph/doc/rados/configuration/osd-config-ref.rst b/ceph/doc/rados/configuration/osd-config-ref.rst index 15b78d583..7ecb6a722 100644 --- a/ceph/doc/rados/configuration/osd-config-ref.rst +++ b/ceph/doc/rados/configuration/osd-config-ref.rst @@ -335,6 +335,22 @@ scrubbing operations. :Default: 512 KB. ``524288`` +``osd scrub auto repair`` + +:Description: Setting this to ``true`` will enable automatic pg repair when errors + are found in deep-scrub. However, if more than ``osd scrub auto repair num errors`` + errors are found a repair is NOT performed. +:Type: Boolean +:Default: ``false`` + + +``osd scrub auto repair num errors`` + +:Description: Auto repair will not occur if more than this many errors are found. +:Type: 32-bit Integer +:Default: ``5`` + + .. index:: OSD; operations settings Operations @@ -401,8 +417,7 @@ recovery operations to ensure optimal performance during recovery. ``osd client op priority`` -:Description: The priority set for client operations. It is relative to - ``osd recovery op priority``. +:Description: The priority set for client operations. :Type: 32-bit Integer :Default: ``63`` @@ -411,8 +426,7 @@ recovery operations to ensure optimal performance during recovery. ``osd recovery op priority`` -:Description: The priority set for recovery operations. It is relative to - ``osd client op priority``. +:Description: The priority set for recovery operations, if not specified by the pool's ``recovery_op_priority``. :Type: 32-bit Integer :Default: ``3`` @@ -421,23 +435,70 @@ recovery operations to ensure optimal performance during recovery. ``osd scrub priority`` -:Description: The priority set for scrub operations. It is relative to - ``osd client op priority``. +:Description: The default priority set for a scheduled scrub work queue when the + pool doesn't specify a value of ``scrub_priority``. This can be + boosted to the value of ``osd client op priority`` when scrub is + blocking client operations. :Type: 32-bit Integer :Default: ``5`` :Valid Range: 1-63 +``osd requested scrub priority`` + +:Description: The priority set for user requested scrub on the work queue. If + this value were to be smaller than ``osd client op priority`` it + can be boosted to the value of ``osd client op priority`` when + scrub is blocking client operations. + +:Type: 32-bit Integer +:Default: ``120`` + + ``osd snap trim priority`` -:Description: The priority set for snap trim operations. It is relative to - ``osd client op priority``. +:Description: The priority set for the snap trim work queue. :Type: 32-bit Integer :Default: ``5`` :Valid Range: 1-63 +``osd snap trim sleep`` + +:Description: Time in seconds to sleep before next snap trim op. + Increasing this value will slow down snap trimming. + This option overrides backend specific variants. + +:Type: Float +:Default: ``0`` + + +``osd snap trim sleep hdd`` + +:Description: Time in seconds to sleep before next snap trim op + for HDDs. + +:Type: Float +:Default: ``5`` + + +``osd snap trim sleep ssd`` + +:Description: Time in seconds to sleep before next snap trim op + for SSDs. + +:Type: Float +:Default: ``0`` + + +``osd snap trim sleep hybrid`` + +:Description: Time in seconds to sleep before next snap trim op + when osd data is on HDD and osd journal is on SSD. + +:Type: Float +:Default: ``2`` ``osd op thread timeout`` @@ -455,49 +516,6 @@ recovery operations to ensure optimal performance during recovery. :Default: ``30`` -``osd disk threads`` - -:Description: The number of disk threads, which are used to perform background - disk intensive OSD operations such as scrubbing and snap - trimming. - -:Type: 32-bit Integer -:Default: ``1`` - -``osd disk thread ioprio class`` - -:Description: Warning: it will only be used if both ``osd disk thread - ioprio class`` and ``osd disk thread ioprio priority`` are - set to a non default value. Sets the ioprio_set(2) I/O - scheduling ``class`` for the disk thread. Acceptable - values are ``idle``, ``be`` or ``rt``. The ``idle`` - class means the disk thread will have lower priority - than any other thread in the OSD. This is useful to slow - down scrubbing on an OSD that is busy handling client - operations. ``be`` is the default and is the same - priority as all other threads in the OSD. ``rt`` means - the disk thread will have precendence over all other - threads in the OSD. Note: Only works with the Linux Kernel - CFQ scheduler. Since Jewel scrubbing is no longer carried - out by the disk iothread, see osd priority options instead. -:Type: String -:Default: the empty string - -``osd disk thread ioprio priority`` - -:Description: Warning: it will only be used if both ``osd disk thread - ioprio class`` and ``osd disk thread ioprio priority`` are - set to a non default value. It sets the ioprio_set(2) - I/O scheduling ``priority`` of the disk thread ranging - from 0 (highest) to 7 (lowest). If all OSDs on a given - host were in class ``idle`` and compete for I/O - (i.e. due to controller congestion), it can be used to - lower the disk thread priority of one OSD to 7 so that - another OSD with priority 0 can have priority. - Note: Only works with the Linux Kernel CFQ scheduler. -:Type: Integer in the range of 0 to 7 or -1 if not to be used. -:Default: ``-1`` - ``osd op history size`` :Description: The maximum number of completed operations to track. @@ -971,6 +989,16 @@ perform well in a degraded state. :Type: Float :Default: ``0.025`` + +``osd recovery priority`` + +:Description: The default priority set for recovery work queue. Not + related to a pool's ``recovery_priority``. + +:Type: 32-bit Integer +:Default: ``5`` + + Tiering ======= diff --git a/ceph/doc/rados/configuration/pool-pg-config-ref.rst b/ceph/doc/rados/configuration/pool-pg-config-ref.rst index 082955b8d..74bb39342 100644 --- a/ceph/doc/rados/configuration/pool-pg-config-ref.rst +++ b/ceph/doc/rados/configuration/pool-pg-config-ref.rst @@ -264,6 +264,20 @@ Ceph configuration file. :Type: Float :Default: ``2`` +``osd recovery priority`` + +:Description: Priority of recovery in the work queue. + +:Type: Integer +:Default: ``5`` + +``osd recovery op priority`` + +:Description: Default priority used for recovery operations if pool doesn't override. + +:Type: Integer +:Default: ``3`` + .. _pool: ../../operations/pools .. _Monitoring OSDs and PGs: ../../operations/monitoring-osd-pg#peering .. _Weighting Bucket Items: ../../operations/crush-map#weightingbucketitems diff --git a/ceph/doc/rados/operations/health-checks.rst b/ceph/doc/rados/operations/health-checks.rst index e141f6bcd..2eb4623be 100644 --- a/ceph/doc/rados/operations/health-checks.rst +++ b/ceph/doc/rados/operations/health-checks.rst @@ -218,6 +218,59 @@ You can either raise the pool quota with:: or delete some existing data to reduce utilization. +BLUEFS_AVAILABLE_SPACE +______________________ + +To check how much space is free for BlueFS do:: + + ceph daemon osd.123 bluestore bluefs available + +This will output up to 3 values: `BDEV_DB free`, `BDEV_SLOW free` and +`available_from_bluestore`. `BDEV_DB` and `BDEV_SLOW` report amount of space that +has been acquired by BlueFS and is considered free. Value `available_from_bluestore` +denotes ability of BlueStore to relinquish more space to BlueFS. +It is normal that this value is different from amount of BlueStore free space, as +BlueFS allocation unit is typically larger than BlueStore allocation unit. +This means that only part of BlueStore free space will be acceptable for BlueFS. + +BLUEFS_LOW_SPACE +_________________ + +If BlueFS is running low on available free space and there is little +`available_from_bluestore` one can consider reducing BlueFS allocation unit size. +To simulate available space when allocation unit is different do:: + + ceph daemon osd.123 bluestore bluefs available + +BLUESTORE_FRAGMENTATION +_______________________ + +As BlueStore works free space on underlying storage will get fragmented. +This is normal and unavoidable but excessive fragmentation will cause slowdown. +To inspect BlueStore fragmentation one can do:: + + ceph daemon osd.123 bluestore allocator score block + +Score is given in [0-1] range. +[0.0 .. 0.4] tiny fragmentation +[0.4 .. 0.7] small, acceptable fragmentation +[0.7 .. 0.9] considerable, but safe fragmentation +[0.9 .. 1.0] severe fragmentation, may impact BlueFS ability to get space from BlueStore + +If detailed report of free fragments is required do:: + + ceph daemon osd.123 bluestore allocator dump block + +In case when handling OSD process that is not running fragmentation can be +inspected with `ceph-bluestore-tool`. +Get fragmentation score:: + + ceph-bluestore-tool --path /var/lib/ceph/osd/ceph-123 --allocator block free-score + +And dump detailed free chunks:: + + ceph-bluestore-tool --path /var/lib/ceph/osd/ceph-123 --allocator block free-dump + Data health (pools & placement groups) -------------------------------------- @@ -355,6 +408,12 @@ Please refer to :doc:`placement-groups#Choosing-the-number-of-Placement-Groups` for more information. +TOO_FEW_OSDS +____________ + +The number of OSDs in the cluster is below the configurable +threshold of ``osd_pool_default_size``. + SMALLER_PGP_NUM _______________ @@ -525,3 +584,36 @@ happen if they are misplaced or degraded (see *PG_AVAILABILITY* and You can manually initiate a scrub of a clean PG with:: ceph pg deep-scrub + + +Miscellaneous +------------- + +TELEMETRY_CHANGED +_________________ + +Telemetry has been enabled, but the contents of the telemetry report +have changed since that time, so telemetry reports will not be sent. + +The Ceph developers periodically revise the telemetry feature to +include new and useful information, or to remove information found to +be useless or sensitive. If any new information is included in the +report, Ceph will require the administrator to re-enable telemetry to +ensure they have an opportunity to (re)review what information will be +shared. + +To review the contents of the telemetry report,:: + + ceph telemetry show + +Note that the telemetry report consists of several optional channels +that may be independently enabled or disabled. For more information, see +:ref:`telemetry`. + +To re-enable telemetry (and make this warning go away),:: + + ceph telemetry on + +To disable telemetry (and make this warning go away),:: + + ceph telemetry off diff --git a/ceph/doc/rados/operations/monitoring-osd-pg.rst b/ceph/doc/rados/operations/monitoring-osd-pg.rst index 0107e341d..ab9da32c5 100644 --- a/ceph/doc/rados/operations/monitoring-osd-pg.rst +++ b/ceph/doc/rados/operations/monitoring-osd-pg.rst @@ -230,15 +230,15 @@ few cases: Placement group IDs consist of the pool number (not pool name) followed by a period (.) and the placement group ID--a hexadecimal number. You can view pool numbers and their names from the output of ``ceph osd - lspools``. For example, the default pool ``rbd`` corresponds to - pool number ``0``. A fully qualified placement group ID has the + lspools``. For example, the first pool created corresponds to + pool number ``1``. A fully qualified placement group ID has the following form:: {pool-num}.{pg-id} And it typically looks like this:: - 0.1f + 1.1f To retrieve a list of placement groups, execute the following:: @@ -488,19 +488,19 @@ requests when it is ready. During the backfill operations, you may see one of several states: ``backfill_wait`` indicates that a backfill operation is pending, but is not -underway yet; ``backfill`` indicates that a backfill operation is underway; -and, ``backfill_too_full`` indicates that a backfill operation was requested, +underway yet; ``backfilling`` indicates that a backfill operation is underway; +and, ``backfill_toofull`` indicates that a backfill operation was requested, but couldn't be completed due to insufficient storage capacity. When a placement group cannot be backfilled, it may be considered ``incomplete``. Ceph provides a number of settings to manage the load spike associated with reassigning placement groups to an OSD (especially a new OSD). By default, -``osd_max_backfills`` sets the maximum number of concurrent backfills to or from -an OSD to 10. The ``backfill full ratio`` enables an OSD to refuse a +``osd_max_backfills`` sets the maximum number of concurrent backfills to and from +an OSD to 1. The ``backfill full ratio`` enables an OSD to refuse a backfill request if the OSD is approaching its full ratio (90%, by default) and change with ``ceph osd set-backfillfull-ratio`` comand. If an OSD refuses a backfill request, the ``osd backfill retry interval`` -enables an OSD to retry the request (after 10 seconds, by default). OSDs can +enables an OSD to retry the request (after 30 seconds, by default). OSDs can also set ``osd backfill scan min`` and ``osd backfill scan max`` to manage scan intervals (64 and 512, by default). @@ -593,7 +593,7 @@ location, all you need is the object name and the pool name. For example:: Ceph should output the object's location. For example:: - osdmap e537 pool 'data' (0) object 'test-object-1' -> pg 0.d1743484 (0.4) -> up [1,0] acting [1,0] + osdmap e537 pool 'data' (1) object 'test-object-1' -> pg 1.d1743484 (1.4) -> up [1,0] acting [1,0] To remove the test object, simply delete it using the ``rados rm`` command. For example:: diff --git a/ceph/doc/rados/operations/monitoring.rst b/ceph/doc/rados/operations/monitoring.rst index 603e8905e..290c2ce81 100644 --- a/ceph/doc/rados/operations/monitoring.rst +++ b/ceph/doc/rados/operations/monitoring.rst @@ -159,6 +159,114 @@ to a health state: 2017-07-25 10:11:13.535493 mon.a mon.0 172.21.9.34:6789/0 110 : cluster [INF] Health check cleared: PG_DEGRADED (was: Degraded data redundancy: 2 pgs unclean, 2 pgs degraded, 2 pgs undersized) 2017-07-25 10:11:13.535577 mon.a mon.0 172.21.9.34:6789/0 111 : cluster [INF] Cluster is now healthy +Network Performance Checks +-------------------------- + +Ceph OSDs send heartbeat ping messages amongst themselves to monitor daemon availability. We +also use the response times to monitor network performance. +While it is possible that a busy OSD could delay a ping response, we can assume +that if a network switch fails mutiple delays will be detected between distinct pairs of OSDs. + +By default we will warn about ping times which exceed 1 second (1000 milliseconds). + +:: + + HEALTH_WARN Long heartbeat ping times on back interface seen, longest is 1118.001 msec + +The health detail will add the combination of OSDs are seeing the delays and by how much. There is a limit of 10 +detail line items. + +:: + + [WRN] OSD_SLOW_PING_TIME_BACK: Long heartbeat ping times on back interface seen, longest is 1118.001 msec + Slow heartbeat ping on back interface from osd.0 to osd.1 1118.001 msec + Slow heartbeat ping on back interface from osd.0 to osd.2 1030.123 msec + Slow heartbeat ping on back interface from osd.2 to osd.1 1015.321 msec + Slow heartbeat ping on back interface from osd.1 to osd.0 1010.456 msec + +To see even more detail and a complete dump of network performance information the ``dump_osd_network`` command can be used. Typically, this would be +sent to a mgr, but it can be limited to a particular OSD's interactions by issuing it to any OSD. The current threshold which defaults to 1 second +(1000 milliseconds) can be overridden as an argument in milliseconds. + +The following command will show all gathered network performance data by specifying a threshold of 0 and sending to the mgr. + +:: + + $ ceph daemon /var/run/ceph/ceph-mgr.x.asok dump_osd_network 0 + { + "threshold": 0, + "entries": [ + { + "last update": "Wed Sep 4 17:04:49 2019", + "stale": false, + "from osd": 2, + "to osd": 0, + "interface": "front", + "average": { + "1min": 1.023, + "5min": 0.860, + "15min": 0.883 + }, + "min": { + "1min": 0.818, + "5min": 0.607, + "15min": 0.607 + }, + "max": { + "1min": 1.164, + "5min": 1.173, + "15min": 1.544 + }, + "last": 0.924 + }, + { + "last update": "Wed Sep 4 17:04:49 2019", + "stale": false, + "from osd": 2, + "to osd": 0, + "interface": "back", + "average": { + "1min": 0.968, + "5min": 0.897, + "15min": 0.830 + }, + "min": { + "1min": 0.860, + "5min": 0.563, + "15min": 0.502 + }, + "max": { + "1min": 1.171, + "5min": 1.216, + "15min": 1.456 + }, + "last": 0.845 + }, + { + "last update": "Wed Sep 4 17:04:48 2019", + "stale": false, + "from osd": 0, + "to osd": 1, + "interface": "front", + "average": { + "1min": 0.965, + "5min": 0.811, + "15min": 0.850 + }, + "min": { + "1min": 0.650, + "5min": 0.488, + "15min": 0.466 + }, + "max": { + "1min": 1.252, + "5min": 1.252, + "15min": 1.362 + }, + "last": 0.791 + }, + ... + Detecting configuration issues ============================== diff --git a/ceph/doc/rados/operations/pools.rst b/ceph/doc/rados/operations/pools.rst index ae569f92a..f3e8b9e6a 100644 --- a/ceph/doc/rados/operations/pools.rst +++ b/ceph/doc/rados/operations/pools.rst @@ -350,7 +350,7 @@ You may set values for the following keys: ``crush_rule`` :Description: The rule to use for mapping object placement in the cluster. -:Type: Integer +:Type: String .. _allow_ec_overwrites: @@ -603,6 +603,27 @@ You may set values for the following keys: :Default: ``0`` +.. _recovery_priority: + +``recovery_priority`` + +:Description: When a value is set it will boost the computed reservation priority + by this amount. This value should be less than 30. + +:Type: Integer +:Default: ``0`` + + +.. _recovery_op_priority: + +``recovery_op_priority`` + +:Description: Specify the recovery operation priority for this pool instead of ``osd_recovery_op_priority``. + +:Type: Integer +:Default: ``0`` + + Get Pool Values =============== @@ -757,6 +778,20 @@ You may get values for the following keys: :Type: Boolean +``recovery_priority`` + +:Description: see recovery_priority_ + +:Type: Integer + + +``recovery_op_priority`` + +:Description: see recovery_op_priority_ + +:Type: Integer + + Set the Number of Object Replicas ================================= diff --git a/ceph/doc/rados/operations/upmap.rst b/ceph/doc/rados/operations/upmap.rst index 58f632261..8bad0d959 100644 --- a/ceph/doc/rados/operations/upmap.rst +++ b/ceph/doc/rados/operations/upmap.rst @@ -23,14 +23,12 @@ use with:: ceph features -A word of caution +Balancer module ----------------- -This is a new feature and not very user friendly. At the time of this -writing we are working on a new `balancer` module for ceph-mgr that -will eventually do all of this automatically. +The new `balancer` module for ceph-mgr will automatically balance +the number of PGs per OSD. See ``Balancer`` -Until then, Offline optimization -------------------- @@ -43,7 +41,9 @@ Upmap entries are updated with an offline optimizer built into ``osdmaptool``. #. Run the optimizer:: - osdmaptool om --upmap out.txt [--upmap-pool ] [--upmap-max ] [--upmap-deviation ] + osdmaptool om --upmap out.txt [--upmap-pool ] + [--upmap-max ] [--upmap-deviation ] + [--upmap-active] It is highly recommended that optimization be done for each pool individually, or for sets of similarly-utilized pools. You can @@ -52,24 +52,34 @@ Upmap entries are updated with an offline optimizer built into ``osdmaptool``. kind of data (e.g., RBD image pools, yes; RGW index pool and RGW data pool, no). - The ``max-count`` value is the maximum number of upmap entries to - identify in the run. The default is 100, but you may want to make - this a smaller number so that the tool completes more quickly (but - does less work). If it cannot find any additional changes to make - it will stop early (i.e., when the pool distribution is perfect). + The ``max-optimizations`` value is the maximum number of upmap entries to + identify in the run. The default is `10` like the ceph-mgr balancer module, + but you should use a larger number if you are doing offline optimization. + If it cannot find any additional changes to make it will stop early + (i.e., when the pool distribution is perfect). - The ``max-deviation`` value defaults to `.01` (i.e., 1%). If an OSD - utilization varies from the average by less than this amount it - will be considered perfect. + The ``max-deviation`` value defaults to `5`. If an OSD PG count + varies from the computed target number by less than or equal + to this amount it will be considered perfect. -#. The proposed changes are written to the output file ``out.txt`` in - the example above. These are normal ceph CLI commands that can be - run to apply the changes to the cluster. This can be done with:: + The ``--upmap-active`` option simulates the behavior of the active + balancer in upmap mode. It keeps cycling until the OSDs are balanced + and reports how many rounds and how long each round is taking. The + elapsed time for rounds indicates the CPU load ceph-mgr will be + consuming when it tries to compute the next optimization plan. + +#. Apply the changes:: source out.txt + The proposed changes are written to the output file ``out.txt`` in + the example above. These are normal ceph CLI commands that can be + run to apply the changes to the cluster. + + The above steps can be repeated as many times as necessary to achieve a perfect distribution of PGs for each set of pools. You can see some (gory) details about what the tool is doing by -passing ``--debug-osd 10`` to ``osdmaptool``. +passing ``--debug-osd 10`` and even more with ``--debug-crush 10`` +to ``osdmaptool``. diff --git a/ceph/doc/rados/troubleshooting/log-and-debug.rst b/ceph/doc/rados/troubleshooting/log-and-debug.rst index c91f27218..cc7709a75 100644 --- a/ceph/doc/rados/troubleshooting/log-and-debug.rst +++ b/ceph/doc/rados/troubleshooting/log-and-debug.rst @@ -513,7 +513,7 @@ RADOS Gateway :Description: Enable logging of RGW's bandwidth usage. :Type: Boolean :Required: No -:Default: ``true`` +:Default: ``false`` ``rgw usage log flush threshold`` diff --git a/ceph/doc/radosgw/frontends.rst b/ceph/doc/radosgw/frontends.rst index 7c0b2cced..1bcbe2eda 100644 --- a/ceph/doc/radosgw/frontends.rst +++ b/ceph/doc/radosgw/frontends.rst @@ -57,6 +57,19 @@ Options :Type: String :Default: None +``tcp_nodelay`` + +:Description: If set the socket option will disable Nagle's algorithm on + the connection which means that packets will be sent as soon + as possible instead of waiting for a full buffer or timeout to occur. + + ``1`` Disable Nagel's algorithm for all sockets. + + ``0`` Keep the default: Nagel's algorithm enabled. + +:Type: Integer (0 or 1) +:Default: 0 + Civetweb ======== diff --git a/ceph/doc/radosgw/layout.rst b/ceph/doc/radosgw/layout.rst index 04a525b6a..a48a995dd 100644 --- a/ceph/doc/radosgw/layout.rst +++ b/ceph/doc/radosgw/layout.rst @@ -42,8 +42,7 @@ Some variables have been used in above commands, they are: - bucket: Holds a mapping between bucket name and bucket instance id - bucket.instance: Holds bucket instance information[2] -Every metadata entry is kept on a single rados object. -See below for implementation defails. +Every metadata entry is kept on a single rados object. See below for implementation details. Note that the metadata is not indexed. When listing a metadata section we do a rados pgls operation on the containing pool. diff --git a/ceph/doc/radosgw/multisite.rst b/ceph/doc/radosgw/multisite.rst index 0c2c44258..5665c837e 100644 --- a/ceph/doc/radosgw/multisite.rst +++ b/ceph/doc/radosgw/multisite.rst @@ -337,14 +337,17 @@ Pull the Realm -------------- Using the URL path, access key and secret of the master zone in the -master zone group, pull the realm to the host. To pull a non-default -realm, specify the realm using the ``--rgw-realm`` or ``--realm-id`` -configuration options. +master zone group, pull the realm configuration to the host. To pull a +non-default realm, specify the realm using the ``--rgw-realm`` or +``--realm-id`` configuration options. :: # radosgw-admin realm pull --url={url-to-master-zone-gateway} --access-key={access-key} --secret={secret} +.. note:: Pulling the realm also retrieves the remote's current period + configuration, and makes it the current period on this host as well. + If this realm is the default realm or the only realm, make the realm the default realm. @@ -352,22 +355,6 @@ default realm. # radosgw-admin realm default --rgw-realm={realm-name} -Pull the Period ---------------- - -Using the URL path, access key and secret of the master zone in the -master zone group, pull the period to the host. To pull a period from a -non-default realm, specify the realm using the ``--rgw-realm`` or -``--realm-id`` configuration options. - -:: - - # radosgw-admin period pull --url={url-to-master-zone-gateway} --access-key={access-key} --secret={secret} - - -.. note:: Pulling the period retrieves the latest version of the zone group - and zone configurations for the realm. - Create a Secondary Zone ----------------------- @@ -582,7 +569,7 @@ disaster recovery. :: # radosgw-admin zone modify --rgw-zone={zone-name} --master --default \ - --read-only=False + --read-only=false 2. Update the period to make the changes take effect. @@ -598,13 +585,13 @@ disaster recovery. If the former master zone recovers, revert the operation. -1. From the recovered zone, pull the period from the current master - zone. +1. From the recovered zone, pull the latest realm configuration + from the current master zone. :: - # radosgw-admin period pull --url={url-to-master-zone-gateway} \ - --access-key={access-key} --secret={secret} + # radosgw-admin realm pull --url={url-to-master-zone-gateway} \ + --access-key={access-key} --secret={secret} 2. Make the recovered zone the master and default zone. diff --git a/ceph/doc/radosgw/placement.rst b/ceph/doc/radosgw/placement.rst index ce9ecbc2e..5878eb207 100644 --- a/ceph/doc/radosgw/placement.rst +++ b/ceph/doc/radosgw/placement.rst @@ -147,6 +147,8 @@ format must be edited manually: $ vi user.json $ radosgw-admin metadata put user: < user.json +.. _s3_bucket_placement: + S3 Bucket Placement ------------------- diff --git a/ceph/doc/radosgw/pools.rst b/ceph/doc/radosgw/pools.rst index 2d88a3c10..a904883b3 100644 --- a/ceph/doc/radosgw/pools.rst +++ b/ceph/doc/radosgw/pools.rst @@ -22,6 +22,8 @@ placement groups for these pools. See `Pools `__ for details on pool creation. +.. _radosgw-pool-namespaces: + Pool Namespaces =============== diff --git a/ceph/doc/radosgw/s3/bucketops.rst b/ceph/doc/radosgw/s3/bucketops.rst index ed1f2a4f6..16bd8fb1c 100644 --- a/ceph/doc/radosgw/s3/bucketops.rst +++ b/ceph/doc/radosgw/s3/bucketops.rst @@ -7,8 +7,6 @@ PUT Bucket Creates a new bucket. To create a bucket, you must have a user ID and a valid AWS Access Key ID to authenticate requests. You may not create buckets as an anonymous user. -.. note:: We do not support request entities for ``PUT /{bucket}`` in this release. - Constraints ~~~~~~~~~~~ In general, bucket names should follow domain name constraints. @@ -37,6 +35,16 @@ Parameters | ``x-amz-acl`` | Canned ACLs. | ``private``, ``public-read``, ``public-read-write``, ``authenticated-read`` | No | +---------------+----------------------+-----------------------------------------------------------------------------+------------+ +Request Entities +~~~~~~~~~~~~~~~~ + ++-------------------------------+-----------+----------------------------------------------------------------+ +| Name | Type | Description | ++===============================+===========+================================================================+ +| ``CreateBucketConfiguration`` | Container | A container for the bucket configuration. | ++-------------------------------+-----------+----------------------------------------------------------------+ +| ``LocationConstraint`` | String | A zonegroup api name, with optional :ref:`s3_bucket_placement` | ++-------------------------------+-----------+----------------------------------------------------------------+ HTTP Response diff --git a/ceph/doc/radosgw/troubleshooting.rst b/ceph/doc/radosgw/troubleshooting.rst index 3e4a05777..fbf984eea 100644 --- a/ceph/doc/radosgw/troubleshooting.rst +++ b/ceph/doc/radosgw/troubleshooting.rst @@ -177,3 +177,34 @@ Also, check to ensure that the default site is disabled. :: +Numerous objects in default.rgw.meta pool +========================================= + +Clusters created prior to *jewel* have a metadata archival feature enabled by default, using the ``default.rgw.meta`` pool. +This archive keeps all old versions of user and bucket metadata, resulting in large numbers of objects in the ``default.rgw.meta`` pool. + +Disabling the Metadata Heap +--------------------------- + +Users who want to disable this feature going forward should set the ``metadata_heap`` field to an empty string ``""``:: + + $ radosgw-admin zone get --rgw-zone=default > zone.json + [edit zone.json, setting "metadata_heap": ""] + $ radosgw-admin zone set --rgw-zone=default --infile=zone.json + $ radosgw-admin period update --commit + +This will stop new metadata from being written to the ``default.rgw.meta`` pool, but does not remove any existing objects or pool. + +Cleaning the Metadata Heap Pool +------------------------------- + +Clusters created prior to *jewel* normally use ``default.rgw.meta`` only for the metadata archival feature. + +However, from *luminous* onwards, radosgw uses :ref:`Pool Namespaces ` within ``default.rgw.meta`` for an entirely different purpose, that is, to store ``user_keys`` and other critical metadata. + +Users should check zone configuration before proceeding any cleanup procedures:: + + $ radosgw-admin zone get --rgw-zone=default | grep default.rgw.meta + [should not match any strings] + +Having confirmed that the pool is not used for any purpose, users may safely delete all objects in the ``default.rgw.meta`` pool, or optionally, delete the entire pool itself. diff --git a/ceph/doc/rbd/qemu-rbd.rst b/ceph/doc/rbd/qemu-rbd.rst index 80c5dcc41..80685cd60 100644 --- a/ceph/doc/rbd/qemu-rbd.rst +++ b/ceph/doc/rbd/qemu-rbd.rst @@ -171,7 +171,7 @@ edit`` to include the ``xmlns:qemu`` value. Then, add a ``qemu:commandline`` block as a child of that domain. The following example shows how to set two devices with ``qemu id=`` to different ``discard_granularity`` values. -.. code-block:: guess +.. code-block:: xml diff --git a/ceph/doc_deps.deb.txt b/ceph/doc_deps.deb.txt index 2b8041bb5..318be6e22 100644 --- a/ceph/doc_deps.deb.txt +++ b/ceph/doc_deps.deb.txt @@ -1,8 +1,8 @@ git gcc -python-dev -python-pip -python-virtualenv +python3-dev +python3-pip +python3-virtualenv doxygen ditaa libxml2-dev @@ -10,4 +10,4 @@ libxslt1-dev graphviz ant zlib1g-dev -cython +cython3 diff --git a/ceph/install-deps.sh b/ceph/install-deps.sh index e73e05f6b..a0944f510 100755 --- a/ceph/install-deps.sh +++ b/ceph/install-deps.sh @@ -19,6 +19,8 @@ if test $(id -u) != 0 ; then fi export LC_ALL=C # the following is vulnerable to i18n +ARCH=$(uname -m) + function munge_ceph_spec_in { local OUTFILE=$1 sed -e 's/@//g' -e 's/%bcond_with make_check/%bcond_without make_check/g' < ceph.spec.in > $OUTFILE @@ -51,18 +53,49 @@ EOF --install /usr/bin/gcc gcc /usr/bin/gcc-${new} 20 \ --slave /usr/bin/g++ g++ /usr/bin/g++-${new} - $SUDO update-alternatives \ - --install /usr/bin/gcc gcc /usr/bin/gcc-${old} 10 \ - --slave /usr/bin/g++ g++ /usr/bin/g++-${old} + if [ -f /usr/bin/g++-${old} ]; then + $SUDO update-alternatives \ + --install /usr/bin/gcc gcc /usr/bin/gcc-${old} 10 \ + --slave /usr/bin/g++ g++ /usr/bin/g++-${old} + fi $SUDO update-alternatives --auto gcc # cmake uses the latter by default - $SUDO ln -nsf /usr/bin/gcc /usr/bin/x86_64-linux-gnu-gcc - $SUDO ln -nsf /usr/bin/g++ /usr/bin/x86_64-linux-gnu-g++ + $SUDO ln -nsf /usr/bin/gcc /usr/bin/${ARCH}-linux-gnu-gcc + $SUDO ln -nsf /usr/bin/g++ /usr/bin/${ARCH}-linux-gnu-g++ } -if [ x`uname`x = xFreeBSDx ]; then +function version_lt { + test $1 != $(echo -e "$1\n$2" | sort -rV | head -n 1) +} + +function ensure_decent_gcc_on_rh { + local old=$(gcc -dumpversion) + local expected=5.1 + local dts_ver=$1 + if version_lt $old $expected; then + if test -t 1; then + # interactive shell + cat < $control - backports="-t $(lsb_release -sc)-backports" + backports="-t $codename-backports" ;; esac @@ -152,47 +185,69 @@ else ;; centos|fedora|rhel|ol|virtuozzo) yumdnf="yum" - builddepcmd="yum-builddep -y" + builddepcmd="yum-builddep -y --setopt=*.skip_if_unavailable=true" if test "$(echo "$VERSION_ID >= 22" | bc)" -ne 0; then yumdnf="dnf" builddepcmd="dnf -y builddep --allowerasing" fi echo "Using $yumdnf to install dependencies" - $SUDO $yumdnf install -y redhat-lsb-core - case $(lsb_release -si) in - Fedora) + if [ "$ID" = "centos" -a "$ARCH" = "aarch64" ]; then + $SUDO yum-config-manager --disable centos-sclo-sclo || true + $SUDO yum-config-manager --disable centos-sclo-rh || true + $SUDO yum remove centos-release-scl || true + fi + + case "$ID" in + fedora) if test $yumdnf = yum; then $SUDO $yumdnf install -y yum-utils fi ;; - CentOS|RedHatEnterpriseServer|VirtuozzoLinux) + centos|rhel|ol|virtuozzo) + MAJOR_VERSION="$(echo $VERSION_ID | cut -d. -f1)" $SUDO yum install -y yum-utils - MAJOR_VERSION=$(lsb_release -rs | cut -f1 -d.) - if test $(lsb_release -si) = RedHatEnterpriseServer ; then - $SUDO yum install subscription-manager - $SUDO subscription-manager repos --enable=rhel-$MAJOR_VERSION-server-optional-rpms + if test $ID = rhel ; then + $SUDO yum-config-manager --enable rhel-$MAJOR_VERSION-server-optional-rpms fi - $SUDO yum-config-manager --add-repo https://dl.fedoraproject.org/pub/epel/$MAJOR_VERSION/x86_64/ - $SUDO yum install --nogpgcheck -y epel-release + rpm --quiet --query epel-release || \ + $SUDO yum -y install --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-$MAJOR_VERSION.noarch.rpm $SUDO rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$MAJOR_VERSION $SUDO rm -f /etc/yum.repos.d/dl.fedoraproject.org* - if test $(lsb_release -si) = CentOS -a $MAJOR_VERSION = 7 ; then - $SUDO yum-config-manager --enable cr - fi - if test $(lsb_release -si) = VirtuozzoLinux -a $MAJOR_VERSION = 7 ; then - $SUDO yum-config-manager --enable cr + if test $ID = centos -a $MAJOR_VERSION = 7 ; then + $SUDO $yumdnf install -y python36-devel + case "$ARCH" in + x86_64) + $SUDO yum -y install centos-release-scl + dts_ver=7 + ;; + aarch64) + $SUDO yum -y install centos-release-scl-rh + $SUDO yum-config-manager --disable centos-sclo-rh + $SUDO yum-config-manager --enable centos-sclo-rh-testing + dts_ver=7 + ;; + esac + elif test $ID = rhel -a $MAJOR_VERSION = 7 ; then + $SUDO yum-config-manager --enable rhel-server-rhscl-7-rpms + dts_ver=7 fi ;; esac munge_ceph_spec_in $DIR/ceph.spec + $SUDO $yumdnf install -y \*rpm-macros $SUDO $builddepcmd $DIR/ceph.spec 2>&1 | tee $DIR/yum-builddep.out + [ ${PIPESTATUS[0]} -ne 0 ] && exit 1 + if [ -n "$dts_ver" ]; then + ensure_decent_gcc_on_rh $dts_ver + fi ! grep -q -i error: $DIR/yum-builddep.out || exit 1 ;; opensuse*|suse|sles) echo "Using zypper to install dependencies" - $SUDO zypper --gpg-auto-import-keys --non-interactive install lsb-release systemd-rpm-macros + zypp_install="zypper --gpg-auto-import-keys --non-interactive install --no-recommends" + $SUDO $zypp_install systemd-rpm-macros munge_ceph_spec_in $DIR/ceph.spec - $SUDO zypper --non-interactive install $(rpmspec -q --buildrequires $DIR/ceph.spec) || exit 1 + $SUDO $zypp_install $(rpmspec -q --buildrequires $DIR/ceph.spec) || exit 1 ;; alpine) # for now we need the testing repo for leveldb @@ -219,8 +274,7 @@ function populate_wheelhouse() { # although pip comes with virtualenv, having a recent version # of pip matters when it comes to using wheel packages - # workaround of https://github.com/pypa/setuptools/issues/1042 - pip --timeout 300 $install 'setuptools >= 0.8,< 36' 'pip >= 7.0' 'wheel >= 0.24' || return 1 + pip --timeout 300 $install 'setuptools >= 0.8' 'pip >= 7.0' 'wheel >= 0.24' || return 1 if test $# != 0 ; then pip --timeout 300 $install $@ || return 1 fi @@ -236,6 +290,9 @@ function activate_virtualenv() { # because CentOS 7 has a buggy old version (v1.10.1) # https://github.com/pypa/virtualenv/issues/463 virtualenv ${env_dir}_tmp + # install setuptools before upgrading virtualenv, as the latter needs + # a recent setuptools for setup commands like `extras_require`. + ${env_dir}_tmp/bin/pip install --upgrade setuptools ${env_dir}_tmp/bin/pip install --upgrade virtualenv ${env_dir}_tmp/bin/virtualenv --python $interpreter $env_dir rm -rf ${env_dir}_tmp @@ -264,6 +321,12 @@ find . -name tox.ini | while read ini ; do ( cd $(dirname $ini) require=$(ls *requirements.txt 2>/dev/null | sed -e 's/^/-r /') + md5=wheelhouse/md5 + if test "$require"; then + if ! test -f $md5 || ! md5sum -c $md5 ; then + rm -rf wheelhouse + fi + fi if test "$require" && ! test -d wheelhouse ; then for interpreter in python2.7 python3 ; do type $interpreter > /dev/null 2>&1 || continue @@ -271,6 +334,7 @@ find . -name tox.ini | while read ini ; do populate_wheelhouse "wheel -w $wip_wheelhouse" $require || exit 1 done mv $wip_wheelhouse wheelhouse + md5sum *requirements.txt > $md5 fi ) done diff --git a/ceph/qa/cephfs/begin.yaml b/ceph/qa/cephfs/begin.yaml index a2e58b0fd..dee64f0af 100644 --- a/ceph/qa/cephfs/begin.yaml +++ b/ceph/qa/cephfs/begin.yaml @@ -1,3 +1,9 @@ tasks: - install: + extra_packages: + - python3-cephfs + # For kernel_untar_build workunit + extra_system_packages: + deb: ['bison', 'flex', 'libelf-dev', 'libssl-dev'] + rpm: ['bison', 'flex', 'elfutils-libelf-devel', 'openssl-devel'] - ceph: diff --git a/ceph/qa/distros/all/centos_7.6.yaml b/ceph/qa/distros/all/centos_7.6.yaml new file mode 100644 index 000000000..a2d4d35c4 --- /dev/null +++ b/ceph/qa/distros/all/centos_7.6.yaml @@ -0,0 +1,3 @@ +os_type: centos +os_version: "7.6" + diff --git a/ceph/qa/distros/all/rhel_7.6.yaml b/ceph/qa/distros/all/rhel_7.6.yaml new file mode 100644 index 000000000..806e1fe30 --- /dev/null +++ b/ceph/qa/distros/all/rhel_7.6.yaml @@ -0,0 +1,3 @@ +os_type: rhel +os_version: "7.6" + diff --git a/ceph/qa/packages/packages.yaml b/ceph/qa/packages/packages.yaml index 31fb66aa9..6d5f7b09a 100644 --- a/ceph/qa/packages/packages.yaml +++ b/ceph/qa/packages/packages.yaml @@ -30,8 +30,6 @@ ceph: - rbd-fuse-dbg - rbd-mirror-dbg - rbd-nbd-dbg - - python3-cephfs - - python3-rados rpm: - ceph-radosgw - ceph-test @@ -45,5 +43,3 @@ ceph: - python-ceph - rbd-fuse - ceph-debuginfo - - python34-cephfs - - python34-rados diff --git a/ceph/qa/standalone/ceph-helpers.sh b/ceph/qa/standalone/ceph-helpers.sh index 9a4bae2a5..472b1a7a8 100755 --- a/ceph/qa/standalone/ceph-helpers.sh +++ b/ceph/qa/standalone/ceph-helpers.sh @@ -491,15 +491,15 @@ function test_run_mon() { setup $dir || return 1 run_mon $dir a --mon-initial-members=a || return 1 - create_rbd_pool || return 1 - # rbd has not been deleted / created, hence it has pool id 0 - ceph osd dump | grep "pool 1 'rbd'" || return 1 + ceph mon dump | grep "mon.a" || return 1 kill_daemons $dir || return 1 - run_mon $dir a || return 1 + run_mon $dir a --osd_pool_default_size=3 || return 1 + run_osd $dir 0 || return 1 + run_osd $dir 1 || return 1 + run_osd $dir 2 || return 1 create_rbd_pool || return 1 - # rbd has been deleted / created, hence it does not have pool id 0 - ! ceph osd dump | grep "pool 1 'rbd'" || return 1 + ceph osd dump | grep "pool 1 'rbd'" || return 1 local size=$(CEPH_ARGS='' ceph --format=json daemon $(get_asok_path mon.a) \ config get osd_pool_default_size) test "$size" = '{"osd_pool_default_size":"3"}' || return 1 @@ -563,6 +563,7 @@ function run_mgr() { --admin-socket=$(get_asok_path) \ --run-dir=$dir \ --pid-file=$dir/\$name.pid \ + --mgr-module-path=$(realpath ${CEPH_ROOT}/src/pybind/mgr) \ "$@" || return 1 } @@ -1460,11 +1461,12 @@ function test_wait_for_clean() { local dir=$1 setup $dir || return 1 - run_mon $dir a --osd_pool_default_size=1 || return 1 + run_mon $dir a --osd_pool_default_size=2 || return 1 + run_osd $dir 0 || return 1 run_mgr $dir x || return 1 create_rbd_pool || return 1 ! TIMEOUT=1 wait_for_clean || return 1 - run_osd $dir 0 || return 1 + run_osd $dir 1 || return 1 wait_for_clean || return 1 teardown $dir || return 1 } @@ -1507,12 +1509,20 @@ function test_wait_for_health_ok() { local dir=$1 setup $dir || return 1 - run_mon $dir a --osd_pool_default_size=1 --osd_failsafe_full_ratio=.99 --mon_pg_warn_min_per_osd=0 || return 1 + run_mon $dir a --osd_failsafe_full_ratio=.99 --mon_pg_warn_min_per_osd=0 || return 1 run_mgr $dir x --mon_pg_warn_min_per_osd=0 || return 1 + # start osd_pool_default_size OSDs run_osd $dir 0 || return 1 + run_osd $dir 1 || return 1 + run_osd $dir 2 || return 1 kill_daemons $dir TERM osd || return 1 + ceph osd down 0 || return 1 + # expect TOO_FEW_OSDS warning ! TIMEOUT=1 wait_for_health_ok || return 1 + # resurrect all OSDs activate_osd $dir 0 || return 1 + activate_osd $dir 1 || return 1 + activate_osd $dir 2 || return 1 wait_for_health_ok || return 1 teardown $dir || return 1 } @@ -1878,7 +1888,7 @@ function test_flush_pg_stats() local jq_filter='.pools | .[] | select(.name == "rbd") | .stats' raw_bytes_used=`ceph df detail --format=json | jq "$jq_filter.raw_bytes_used"` bytes_used=`ceph df detail --format=json | jq "$jq_filter.bytes_used"` - test $raw_bytes_used > 0 || return 1 + test $raw_bytes_used -gt 0 || return 1 test $raw_bytes_used == $bytes_used || return 1 teardown $dir } diff --git a/ceph/qa/standalone/erasure-code/test-erasure-code.sh b/ceph/qa/standalone/erasure-code/test-erasure-code.sh index 452161dbd..f2f6b58ab 100755 --- a/ceph/qa/standalone/erasure-code/test-erasure-code.sh +++ b/ceph/qa/standalone/erasure-code/test-erasure-code.sh @@ -308,7 +308,7 @@ function TEST_chunk_mapping() { ceph osd erasure-code-profile set remap-profile \ plugin=lrc \ - layers='[ [ "_DD", "" ] ]' \ + layers='[ [ "cDD", "" ] ]' \ mapping='_DD' \ crush-steps='[ [ "choose", "osd", 0 ] ]' || return 1 ceph osd erasure-code-profile get remap-profile diff --git a/ceph/qa/standalone/erasure-code/test-erasure-eio.sh b/ceph/qa/standalone/erasure-code/test-erasure-eio.sh index ce037aaca..1647033d1 100755 --- a/ceph/qa/standalone/erasure-code/test-erasure-eio.sh +++ b/ceph/qa/standalone/erasure-code/test-erasure-eio.sh @@ -26,13 +26,14 @@ function run() { export CEPH_ARGS CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " CEPH_ARGS+="--mon-host=$CEPH_MON " + CEPH_ARGS+="--osd-objectstore=filestore " local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} for func in $funcs ; do setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 - create_rbd_pool || return 1 + create_pool rbd 4 || return 1 # check that erasure code plugins are preloaded CEPH_ARGS='' ceph --admin-daemon $(get_asok_path mon.a) log flush || return 1 diff --git a/ceph/qa/standalone/mgr/balancer.sh b/ceph/qa/standalone/mgr/balancer.sh new file mode 100755 index 000000000..cd7c0e8a3 --- /dev/null +++ b/ceph/qa/standalone/mgr/balancer.sh @@ -0,0 +1,209 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2019 Red Hat +# +# Author: David Zafman +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Public License for more details. +# +source $CEPH_ROOT/qa/standalone/ceph-helpers.sh + +function run() { + local dir=$1 + shift + + export CEPH_MON="127.0.0.1:7102" # git grep '\<7102\>' : there must be only one + export CEPH_ARGS + CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " + CEPH_ARGS+="--mon-host=$CEPH_MON " + + local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} + for func in $funcs ; do + $func $dir || return 1 + done +} + +TEST_POOL1=test1 +TEST_POOL2=test2 + +function TEST_balancer() { + local dir=$1 + + setup $dir || return 1 + run_mon $dir a || return 1 + run_mgr $dir x || return 1 + run_osd $dir 0 || return 1 + run_osd $dir 1 || return 1 + run_osd $dir 2 || return 1 + create_pool $TEST_POOL1 8 + create_pool $TEST_POOL2 8 + + wait_for_clean || return 1 + + ceph pg dump pgs + ceph osd set-require-min-compat-client luminous + ceph balancer status || return 1 + eval MODE=$(ceph balancer status | jq '.mode') + test $MODE = "none" || return 1 + ACTIVE=$(ceph balancer status | jq '.active') + test $ACTIVE = "false" || return 1 + + ceph balancer ls || return 1 + PLANS=$(ceph balancer ls) + test "$PLANS" = "[]" || return 1 + ceph balancer eval || return 1 + EVAL="$(ceph balancer eval)" + test "$EVAL" = "current cluster score 0.000000 (lower is better)" + ceph balancer eval-verbose || return 1 + + ceph balancer mode crush-compat || return 1 + ceph balancer status || return 1 + eval MODE=$(ceph balancer status | jq '.mode') + test $MODE = "crush-compat" || return 1 + ! ceph balancer optimize plan_crush $TEST_POOL1 || return 1 + ceph balancer status || return 1 + eval RESULT=$(ceph balancer status | jq '.optimize_result') + test "$RESULT" = "Distribution is already perfect" || return 1 + + ceph balancer on || return 1 + ACTIVE=$(ceph balancer status | jq '.active') + test $ACTIVE = "true" || return 1 + sleep 2 + ceph balancer status || return 1 + ceph balancer off || return 1 + ACTIVE=$(ceph balancer status | jq '.active') + test $ACTIVE = "false" || return 1 + sleep 2 + + ceph balancer reset || return 1 + + ceph balancer mode upmap || return 1 + ceph balancer status || return 1 + eval MODE=$(ceph balancer status | jq '.mode') + test $MODE = "upmap" || return 1 + ! ceph balancer optimize plan_upmap $TEST_POOL || return 1 + ceph balancer status || return 1 + eval RESULT=$(ceph balancer status | jq '.optimize_result') + test "$RESULT" = "Unable to find further optimization, or distribution is already perfect" || return 1 + + ceph balancer on || return 1 + ACTIVE=$(ceph balancer status | jq '.active') + test $ACTIVE = "true" || return 1 + sleep 2 + ceph balancer status || return 1 + ceph balancer off || return 1 + ACTIVE=$(ceph balancer status | jq '.active') + test $ACTIVE = "false" || return 1 + + teardown $dir || return 1 +} + +function TEST_balancer2() { + local dir=$1 + TEST_PGS1=118 + TEST_PGS2=132 + TOTAL_PGS=$(expr $TEST_PGS1 + $TEST_PGS2) + OSDS=5 + DEFAULT_REPLICAS=3 + # Integer average of PGS per OSD (70.8), so each OSD >= this + FINAL_PER_OSD1=$(expr \( $TEST_PGS1 \* $DEFAULT_REPLICAS \) / $OSDS) + # Integer average of PGS per OSD (150) + FINAL_PER_OSD2=$(expr \( \( $TEST_PGS1 + $TEST_PGS2 \) \* $DEFAULT_REPLICAS \) / $OSDS) + + CEPH_ARGS+="--debug_osd=20 " + setup $dir || return 1 + run_mon $dir a || return 1 + # Must do this before starting ceph-mgr + ceph config-key set mgr/balancer/upmap_max_deviation 1 + run_mgr $dir x || return 1 + for i in $(seq 0 $(expr $OSDS - 1)) + do + run_osd $dir $i || return 1 + done + + ceph osd set-require-min-compat-client luminous + ceph balancer mode upmap || return 1 + ceph balancer on || return 1 + ceph balancer sleep 5 + + create_pool $TEST_POOL1 $TEST_PGS1 + + wait_for_clean || return 1 + + # Wait up to 2 minutes + OK=no + for i in $(seq 1 25) + do + sleep 5 + if grep -q "Optimization plan is almost perfect" $dir/mgr.x.log + then + OK=yes + break + fi + done + test $OK = "yes" || return 1 + # Plan is found, but PGs still need to move + sleep 30 + ceph osd df + + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[0].pgs') + test $PGS -ge $FINAL_PER_OSD1 || return 1 + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[1].pgs') + test $PGS -ge $FINAL_PER_OSD1 || return 1 + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[2].pgs') + test $PGS -ge $FINAL_PER_OSD1 || return 1 + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[3].pgs') + test $PGS -ge $FINAL_PER_OSD1 || return 1 + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[4].pgs') + test $PGS -ge $FINAL_PER_OSD1 || return 1 + + create_pool $TEST_POOL2 $TEST_PGS2 + + # Wait up to 2 minutes + OK=no + for i in $(seq 1 25) + do + sleep 5 + COUNT=$(grep "Optimization plan is almost perfect" $dir/mgr.x.log | wc -l) + if test $COUNT = "2" + then + OK=yes + break + fi + done + test $OK = "yes" || return 1 + # Plan is found, but PGs still need to move + sleep 30 + ceph osd df + + # We should be with plue or minus 1 of FINAL_PER_OSD2 + # This is because here each pool is balanced independently + MIN=$(expr $FINAL_PER_OSD2 - 1) + MAX=$(expr $FINAL_PER_OSD2 + 1) + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[0].pgs') + test $PGS -ge $MIN -a $PGS -le $MAX || return 1 + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[1].pgs') + test $PGS -ge $MIN -a $PGS -le $MAX || return 1 + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[2].pgs') + test $PGS -ge $MIN -a $PGS -le $MAX || return 1 + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[3].pgs') + test $PGS -ge $MIN -a $PGS -le $MAX || return 1 + PGS=$(ceph osd df --format=json-pretty | jq '.nodes[4].pgs') + test $PGS -ge $MIN -a $PGS -le $MAX || return 1 + + teardown $dir || return 1 +} + +main balancer "$@" + +# Local Variables: +# compile-command: "make -j4 && ../qa/run-standalone.sh balancer.sh" +# End: diff --git a/ceph/qa/standalone/misc/network-ping.sh b/ceph/qa/standalone/misc/network-ping.sh new file mode 100755 index 000000000..19d0d6528 --- /dev/null +++ b/ceph/qa/standalone/misc/network-ping.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +source $CEPH_ROOT/qa/standalone/ceph-helpers.sh + +function run() { + local dir=$1 + shift + + export CEPH_MON="127.0.0.1:7146" # git grep '\<7146\>' : there must be only one + export CEPH_ARGS + CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " + CEPH_ARGS+="--mon-host=$CEPH_MON " + CEPH_ARGS+="--debug_disable_randomized_ping=true " + CEPH_ARGS+="--debug_heartbeat_testing_span=5 " + CEPH_ARGS+="--osd_heartbeat_interval=1 " + local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} + for func in $funcs ; do + setup $dir || return 1 + $func $dir || return 1 + teardown $dir || return 1 + done +} + +function TEST_network_ping_test1() { + local dir=$1 + + run_mon $dir a || return 1 + run_mgr $dir x || return 1 + run_osd $dir 0 || return 1 + run_osd $dir 1 || return 1 + run_osd $dir 2 || return 1 + + sleep 5 + + create_pool foo 16 + + # write some objects + timeout 20 rados bench -p foo 10 write -b 4096 --no-cleanup || return 1 + + # Get 1 cycle worth of ping data "1 minute" + sleep 10 + flush_pg_stats + + CEPH_ARGS='' ceph daemon $(get_asok_path osd.0) dump_osd_network | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "0" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "1000" || return 1 + + CEPH_ARGS='' ceph daemon $(get_asok_path mgr.x) dump_osd_network | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "0" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "1000" || return 1 + + CEPH_ARGS='' ceph daemon $(get_asok_path osd.0) dump_osd_network 0 | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "4" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "0" || return 1 + + CEPH_ARGS='' ceph daemon $(get_asok_path mgr.x) dump_osd_network 0 | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "12" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "0" || return 1 + + # Wait another 4 cycles to get "5 minute interval" + sleep 20 + flush_pg_stats + CEPH_ARGS='' ceph daemon $(get_asok_path osd.0) dump_osd_network | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "0" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "1000" || return 1 + + CEPH_ARGS='' ceph daemon $(get_asok_path mgr.x) dump_osd_network | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "0" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "1000" || return 1 + + CEPH_ARGS='' ceph daemon $(get_asok_path osd.0) dump_osd_network 0 | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "4" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "0" || return 1 + + CEPH_ARGS='' ceph daemon $(get_asok_path mgr.x) dump_osd_network 0 | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "12" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "0" || return 1 + + + # Wait another 10 cycles to get "15 minute interval" + sleep 50 + flush_pg_stats + CEPH_ARGS='' ceph daemon $(get_asok_path osd.0) dump_osd_network | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "0" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "1000" || return 1 + + CEPH_ARGS='' ceph daemon $(get_asok_path mgr.x) dump_osd_network | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "0" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "1000" || return 1 + + CEPH_ARGS='' ceph daemon $(get_asok_path osd.0) dump_osd_network 0 | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "4" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "0" || return 1 + + CEPH_ARGS='' ceph daemon $(get_asok_path mgr.x) dump_osd_network 0 | tee $dir/json + test "$(cat $dir/json | jq '.entries | length')" = "12" || return 1 + test "$(cat $dir/json | jq '.threshold')" = "0" || return 1 + + # Just check the threshold output matches the input + CEPH_ARGS='' ceph daemon $(get_asok_path mgr.x) dump_osd_network 99 | tee $dir/json + test "$(cat $dir/json | jq '.threshold')" = "99" || return 1 + CEPH_ARGS='' ceph daemon $(get_asok_path osd.0) dump_osd_network 98 | tee $dir/json + test "$(cat $dir/json | jq '.threshold')" = "98" || return 1 + + rm -f $dir/json +} + +# Test setting of mon_warn_on_slow_ping_time very low to +# get health warning +function TEST_network_ping_test2() { + local dir=$1 + + export CEPH_ARGS + export EXTRA_OPTS+=" --mon_warn_on_slow_ping_time=0.001" + run_mon $dir a || return 1 + run_mgr $dir x || return 1 + run_osd $dir 0 || return 1 + run_osd $dir 1 || return 1 + run_osd $dir 2 || return 1 + + sleep 5 + + create_pool foo 16 + + # write some objects + timeout 20 rados bench -p foo 10 write -b 4096 --no-cleanup || return 1 + + # Get at least 1 cycle of ping data (this test runs with 5 second cycles of 1 second pings) + sleep 10 + flush_pg_stats + + ceph health | tee $dir/health + grep -q "Long heartbeat" $dir/health || return 1 + + ceph health detail | tee $dir/health + grep -q "OSD_SLOW_PING_TIME_BACK" $dir/health || return 1 + grep -q "OSD_SLOW_PING_TIME_FRONT" $dir/health || return 1 + rm -f $dir/health +} + +main network-ping "$@" + +# Local Variables: +# compile-command: "cd ../.. ; make -j4 && ../qa/run-standalone.sh network-ping.sh" +# End: diff --git a/ceph/qa/standalone/mon/misc.sh b/ceph/qa/standalone/mon/misc.sh index e025e0708..4e0a2b6a1 100755 --- a/ceph/qa/standalone/mon/misc.sh +++ b/ceph/qa/standalone/mon/misc.sh @@ -39,7 +39,6 @@ function TEST_osd_pool_get_set() { setup $dir || return 1 run_mon $dir a || return 1 - create_rbd_pool || return 1 create_pool $TEST_POOL 8 local flag diff --git a/ceph/qa/standalone/mon/osd-crush.sh b/ceph/qa/standalone/mon/osd-crush.sh index 747e30db5..3cd4821f7 100755 --- a/ceph/qa/standalone/mon/osd-crush.sh +++ b/ceph/qa/standalone/mon/osd-crush.sh @@ -210,7 +210,7 @@ function TEST_crush_rename_bucket() { function TEST_crush_reject_empty() { local dir=$1 - run_mon $dir a || return 1 + run_mon $dir a --osd_pool_default_size=1 || return 1 # should have at least one OSD run_osd $dir 0 || return 1 create_rbd_pool || return 1 diff --git a/ceph/qa/standalone/mon/osd-pool-create.sh b/ceph/qa/standalone/mon/osd-pool-create.sh index 5b19c0095..74f07131f 100755 --- a/ceph/qa/standalone/mon/osd-pool-create.sh +++ b/ceph/qa/standalone/mon/osd-pool-create.sh @@ -213,6 +213,7 @@ function TEST_pool_create_rep_expected_num_objects() { setup $dir || return 1 # disable pg dir merge + CEPH_ARGS+="--osd-objectstore=filestore" export CEPH_ARGS run_mon $dir a || return 1 run_osd $dir 0 || return 1 diff --git a/ceph/qa/standalone/osd/osd-backfill-recovery-log.sh b/ceph/qa/standalone/osd/osd-backfill-recovery-log.sh new file mode 100755 index 000000000..fcc57f494 --- /dev/null +++ b/ceph/qa/standalone/osd/osd-backfill-recovery-log.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2019 Red Hat +# +# Author: David Zafman +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library Public License for more details. +# + +source $CEPH_ROOT/qa/standalone/ceph-helpers.sh + +function run() { + local dir=$1 + shift + + # Fix port???? + export CEPH_MON="127.0.0.1:7129" # git grep '\<7129\>' : there must be only one + export CEPH_ARGS + CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " + CEPH_ARGS+="--mon-host=$CEPH_MON --osd_max_backfills=1 --debug_reserver=20 " + + local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} + for func in $funcs ; do + setup $dir || return 1 + $func $dir || return 1 + teardown $dir || return 1 + done +} + + +function _common_test() { + local dir=$1 + local extra_opts="$2" + local loglen="$3" + local dupslen="$4" + local objects="$5" + local moreobjects=${6:-0} + + local OSDS=6 + + run_mon $dir a || return 1 + run_mgr $dir x || return 1 + export CEPH_ARGS + + for osd in $(seq 0 $(expr $OSDS - 1)) + do + run_osd $dir $osd $extra_opts || return 1 + done + + create_pool test 1 1 + + for j in $(seq 1 $objects) + do + rados -p test put obj-${j} /etc/passwd + done + + # Mark out all OSDs for this pool + ceph osd out $(ceph pg dump pgs --format=json | jq '.[0].up[]') + if [ "$moreobjects" != "0" ]; then + for j in $(seq 1 $moreobjects) + do + rados -p test put obj-more-${j} /etc/passwd + done + fi + sleep 1 + wait_for_clean + + newprimary=$(ceph pg dump pgs --format=json | jq '.[0].up_primary') + kill_daemons + + ERRORS=0 + _objectstore_tool_nodown $dir $newprimary --no-mon-config --pgid 1.0 --op log | tee $dir/result.log + LOGLEN=$(jq '.pg_log_t.log | length' $dir/result.log) + if [ $LOGLEN != "$loglen" ]; then + echo "FAILED: Wrong log length got $LOGLEN (expected $loglen)" + ERRORS=$(expr $ERRORS + 1) + fi + DUPSLEN=$(jq '.pg_log_t.dups | length' $dir/result.log) + if [ $DUPSLEN != "$dupslen" ]; then + echo "FAILED: Wrong dups length got $DUPSLEN (expected $dupslen)" + ERRORS=$(expr $ERRORS + 1) + fi + grep "copy_up_to\|copy_after" $dir/osd.*.log + rm -f $dir/result.log + if [ $ERRORS != "0" ]; then + echo TEST FAILED + return 1 + fi +} + + +# Cause copy_up_to() to only partially copy logs, copy additional dups, and trim dups +function TEST_backfill_log_1() { + local dir=$1 + + _common_test $dir "--osd_min_pg_log_entries=1 --osd_max_pg_log_entries=2 --osd_pg_log_dups_tracked=10" 1 9 150 +} + + +# Cause copy_up_to() to only partially copy logs, copy additional dups +function TEST_backfill_log_2() { + local dir=$1 + + _common_test $dir "--osd_min_pg_log_entries=1 --osd_max_pg_log_entries=2" 1 149 150 +} + + +# Cause copy_after() to only copy logs, no dups +function TEST_recovery_1() { + local dir=$1 + + _common_test $dir "--osd_min_pg_log_entries=50 --osd_max_pg_log_entries=50 --osd_pg_log_dups_tracked=60 --osd_pg_log_trim_min=10" 40 0 40 +} + + +# Cause copy_after() to copy logs with dups +function TEST_recovery_2() { + local dir=$1 + + _common_test $dir "--osd_min_pg_log_entries=150 --osd_max_pg_log_entries=150 --osd_pg_log_dups_tracked=3000 --osd_pg_log_trim_min=10" 151 10 141 20 +} + +main osd-backfill-recovery-log "$@" + +# Local Variables: +# compile-command: "make -j4 && ../qa/run-standalone.sh osd-backfill-recovery-log.sh" +# End: diff --git a/ceph/qa/standalone/osd/osd-markdown.sh b/ceph/qa/standalone/osd/osd-markdown.sh index 64157537d..6b7a6321e 100755 --- a/ceph/qa/standalone/osd/osd-markdown.sh +++ b/ceph/qa/standalone/osd/osd-markdown.sh @@ -48,7 +48,7 @@ function markdown_N_impl() { # override any dup setting in the environment to ensure we do this # exactly once (modulo messenger failures, at least; we can't *actually* # provide exactly-once semantics for mon commands). - CEPH_CLI_TEST_DUP_COMMAND=0 ceph osd down 0 + ( unset CEPH_CLI_TEST_DUP_COMMAND ; ceph osd down 0 ) sleep $sleeptime done } diff --git a/ceph/qa/standalone/osd/osd-rep-recov-eio.sh b/ceph/qa/standalone/osd/osd-rep-recov-eio.sh index 3a4785663..bcdca3593 100755 --- a/ceph/qa/standalone/osd/osd-rep-recov-eio.sh +++ b/ceph/qa/standalone/osd/osd-rep-recov-eio.sh @@ -27,13 +27,14 @@ function run() { export CEPH_ARGS CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " CEPH_ARGS+="--mon-host=$CEPH_MON " + CEPH_ARGS+="--osd-objectstore=filestore " local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} for func in $funcs ; do setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 - create_rbd_pool || return 1 + ceph osd pool create foo 8 || return 1 $func $dir || return 1 teardown $dir || return 1 diff --git a/ceph/qa/standalone/scrub/osd-scrub-repair.sh b/ceph/qa/standalone/scrub/osd-scrub-repair.sh index 8b228784e..76772becb 100755 --- a/ceph/qa/standalone/scrub/osd-scrub-repair.sh +++ b/ceph/qa/standalone/scrub/osd-scrub-repair.sh @@ -57,6 +57,7 @@ function run() { CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " CEPH_ARGS+="--mon-host=$CEPH_MON " CEPH_ARGS+="--osd-skip-data-digest=false " + CEPH_ARGS+="--osd-objectstore=filestore " local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} for func in $funcs ; do @@ -490,7 +491,7 @@ function TEST_list_missing_erasure_coded_overwrites() { function TEST_corrupt_scrub_replicated() { local dir=$1 local poolname=csr_pool - local total_objs=18 + local total_objs=19 setup $dir || return 1 run_mon $dir a --osd_pool_default_size=2 || return 1 @@ -512,6 +513,11 @@ function TEST_corrupt_scrub_replicated() { rados --pool $poolname setomapval $objname key-$objname val-$objname || return 1 done + # Increase file 1 MB + 1KB + dd if=/dev/zero of=$dir/new.ROBJ19 bs=1024 count=1025 + rados --pool $poolname put $objname $dir/new.ROBJ19 || return 1 + rm -f $dir/new.ROBJ19 + local pg=$(get_pg $poolname ROBJ0) local primary=$(get_primary $poolname ROBJ0) @@ -631,12 +637,18 @@ function TEST_corrupt_scrub_replicated() { objectstore_tool $dir 1 $objname set-bytes $dir/new.ROBJ18 || return 1 # Make one replica have a different object info, so a full repair must happen too objectstore_tool $dir $osd $objname corrupt-info || return 1 + ;; + + 19) + # Set osd-max-object-size smaller than this object's size esac done local pg=$(get_pg $poolname ROBJ0) + ceph tell osd.\* injectargs -- --osd-max-object-size=1048576 + inject_eio rep data $poolname ROBJ11 $dir 0 || return 1 # shard 0 of [1, 0], osd.1 inject_eio rep mdata $poolname ROBJ12 $dir 1 || return 1 # shard 1 of [1, 0], osd.0 inject_eio rep mdata $poolname ROBJ13 $dir 1 || return 1 # shard 1 of [1, 0], osd.0 @@ -664,9 +676,10 @@ function TEST_corrupt_scrub_replicated() { err_strings[15]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 shard 1 soid 3:ffdb2004:::ROBJ9:head : object info inconsistent " err_strings[16]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 3:c0c86b1d:::ROBJ14:head : no '_' attr" err_strings[17]="log_channel[(]cluster[)] log [[]ERR[]] : scrub [0-9]*[.]0 3:5c7b2c47:::ROBJ16:head : can't decode 'snapset' attr buffer::malformed_input: .* no longer understand old encoding version 3 < 97" - err_strings[18]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 scrub : stat mismatch, got 18/18 objects, 0/0 clones, 17/18 dirty, 17/18 omap, 0/0 pinned, 0/0 hit_set_archive, 0/0 whiteouts, 113/120 bytes, 0/0 hit_set_archive bytes." - err_strings[19]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 scrub 1 missing, 7 inconsistent objects" - err_strings[20]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 scrub 17 errors" + err_strings[18]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 scrub : stat mismatch, got 19/19 objects, 0/0 clones, 18/19 dirty, 18/19 omap, 0/0 pinned, 0/0 hit_set_archive, 0/0 whiteouts, 1049713/1049720 bytes, 0/0 hit_set_archive bytes." + err_strings[19]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 scrub 1 missing, 8 inconsistent objects" + err_strings[20]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 scrub 18 errors" + err_strings[21]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 soid 3:123a5f55:::ROBJ19:head : size 1049600 > 1048576 is too large" for err_string in "${err_strings[@]}" do @@ -1209,6 +1222,69 @@ function TEST_corrupt_scrub_replicated() { ], "union_shard_errors": [] }, + { + "object": { + "name": "ROBJ19", + "nspace": "", + "locator": "", + "snap": "head", + "version": 58 + }, + "errors": [ + "size_too_large" + ], + "union_shard_errors": [], + "selected_object_info": { + "oid": { + "oid": "ROBJ19", + "key": "", + "snapid": -2, + "hash": 2868534344, + "max": 0, + "pool": 3, + "namespace": "" + }, + "version": "63'59", + "prior_version": "63'58", + "last_reqid": "osd.1.0:58", + "user_version": 58, + "size": 1049600, + "mtime": "2019-08-09T23:33:58.340709+0000", + "local_mtime": "2019-08-09T23:33:58.345676+0000", + "lost": 0, + "flags": [ + "dirty", + "omap", + "data_digest", + "omap_digest" + ], + "truncate_seq": 0, + "truncate_size": 0, + "data_digest": "0x3dde0ef3", + "omap_digest": "0xbffddd28", + "expected_object_size": 0, + "expected_write_size": 0, + "alloc_hint_flags": 0, + "manifest": { + "type": 0 + }, + "watchers": {} + }, + "shards": [ + { + "osd": 0, + "primary": false, + "errors": [], + "size": 1049600 + }, + { + "osd": 1, + "primary": true, + "errors": [], + "size": 1049600 + } + ] + }, { "shards": [ { @@ -1325,7 +1401,7 @@ function TEST_corrupt_scrub_replicated() { "version": "79'66", "prior_version": "79'65", "last_reqid": "client.4554.0:1", - "user_version": 74, + "user_version": 79, "size": 7, "mtime": "", "local_mtime": "", @@ -1377,7 +1453,7 @@ function TEST_corrupt_scrub_replicated() { "version": "95'67", "prior_version": "51'64", "last_reqid": "client.4649.0:1", - "user_version": 75, + "user_version": 80, "size": 1, "mtime": "", "local_mtime": "", @@ -1463,7 +1539,7 @@ function TEST_corrupt_scrub_replicated() { "version": "95'67", "prior_version": "51'64", "last_reqid": "client.4649.0:1", - "user_version": 75, + "user_version": 80, "size": 1, "mtime": "", "local_mtime": "", @@ -1536,6 +1612,10 @@ EOF inject_eio rep mdata $poolname ROBJ12 $dir 1 || return 1 # shard 1 of [1, 0], osd.0 inject_eio rep mdata $poolname ROBJ13 $dir 1 || return 1 # shard 1 of [1, 0], osd.0 inject_eio rep data $poolname ROBJ13 $dir 0 || return 1 # shard 0 of [1, 0], osd.1 + + # ROBJ19 won't error this time + ceph tell osd.\* injectargs -- --osd-max-object-size=134217728 + pg_deep_scrub $pg err_strings=() @@ -1562,7 +1642,7 @@ EOF err_strings[20]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 shard 0 soid 3:c0c86b1d:::ROBJ14:head : candidate had a corrupt info" err_strings[21]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 soid 3:c0c86b1d:::ROBJ14:head : failed to pick suitable object info" err_strings[22]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 shard 1 soid 3:ce3f1d6a:::ROBJ1:head : candidate size 9 info size 7 mismatch" - err_strings[23]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 shard 1 soid 3:ce3f1d6a:::ROBJ1:head : data_digest 0x2d4a11c2 != data_digest 0x2ddbf8f5 from shard 0, data_digest 0x2d4a11c2 != data_digest 0x2ddbf8f5 from auth oi 3:ce3f1d6a:::ROBJ1:head[(][0-9]*'[0-9]* osd.1.0:65 dirty|omap|data_digest|omap_digest s 7 uv 3 dd 2ddbf8f5 od f5fba2c6 alloc_hint [[]0 0 0[]][)], size 9 != size 7 from auth oi 3:ce3f1d6a:::ROBJ1:head[(][0-9]*'[0-9]* osd.1.0:[0-9]* dirty|omap|data_digest|omap_digest s 7 uv 3 dd 2ddbf8f5 od f5fba2c6 alloc_hint [[]0 0 0[]][)], size 9 != size 7 from shard 0" + err_strings[23]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 shard 1 soid 3:ce3f1d6a:::ROBJ1:head : data_digest 0x2d4a11c2 != data_digest 0x2ddbf8f5 from shard 0, data_digest 0x2d4a11c2 != data_digest 0x2ddbf8f5 from auth oi 3:ce3f1d6a:::ROBJ1:head[(][0-9]*'[0-9]* osd.1.0:[0-9]* dirty|omap|data_digest|omap_digest s 7 uv 3 dd 2ddbf8f5 od f5fba2c6 alloc_hint [[]0 0 0[]][)], size 9 != size 7 from auth oi 3:ce3f1d6a:::ROBJ1:head[(][0-9]*'[0-9]* osd.1.0:[0-9]* dirty|omap|data_digest|omap_digest s 7 uv 3 dd 2ddbf8f5 od f5fba2c6 alloc_hint [[]0 0 0[]][)], size 9 != size 7 from shard 0" err_strings[24]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 shard 1 soid 3:d60617f9:::ROBJ13:head : candidate had a read error" err_strings[25]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 shard 0 soid 3:d60617f9:::ROBJ13:head : candidate had a stat error" err_strings[26]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 soid 3:d60617f9:::ROBJ13:head : failed to pick suitable object info" @@ -1575,7 +1655,7 @@ EOF err_strings[33]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 shard 0 soid 3:ffdb2004:::ROBJ9:head : object info inconsistent " err_strings[34]="log_channel[(]cluster[)] log [[]ERR[]] : deep-scrub [0-9]*[.]0 3:c0c86b1d:::ROBJ14:head : no '_' attr" err_strings[35]="log_channel[(]cluster[)] log [[]ERR[]] : deep-scrub [0-9]*[.]0 3:5c7b2c47:::ROBJ16:head : can't decode 'snapset' attr buffer::malformed_input: .* no longer understand old encoding version 3 < 97" - err_strings[36]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 deep-scrub : stat mismatch, got 18/18 objects, 0/0 clones, 17/18 dirty, 17/18 omap, 0/0 pinned, 0/0 hit_set_archive, 0/0 whiteouts, 115/116 bytes, 0/0 hit_set_archive bytes." + err_strings[36]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 deep-scrub : stat mismatch, got 19/19 objects, 0/0 clones, 18/19 dirty, 18/19 omap, 0/0 pinned, 0/0 hit_set_archive, 0/0 whiteouts, 1049715/1049716 bytes, 0/0 hit_set_archive bytes." err_strings[37]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 deep-scrub 1 missing, 11 inconsistent objects" err_strings[38]="log_channel[(]cluster[)] log [[]ERR[]] : [0-9]*[.]0 deep-scrub 35 errors" @@ -2798,7 +2878,7 @@ EOF "version": "79'66", "prior_version": "79'65", "last_reqid": "client.4554.0:1", - "user_version": 74, + "user_version": 79, "size": 7, "mtime": "2018-04-05 14:34:05.598688", "local_mtime": "2018-04-05 14:34:05.599698", @@ -2896,7 +2976,7 @@ EOF "version": "119'68", "prior_version": "51'64", "last_reqid": "client.4834.0:1", - "user_version": 76, + "user_version": 81, "size": 3, "mtime": "2018-04-05 14:35:01.500659", "local_mtime": "2018-04-05 14:35:01.502117", @@ -2940,7 +3020,7 @@ EOF "version": "119'68", "prior_version": "51'64", "last_reqid": "client.4834.0:1", - "user_version": 76, + "user_version": 81, "size": 3, "mtime": "2018-04-05 14:35:01.500659", "local_mtime": "2018-04-05 14:35:01.502117", diff --git a/ceph/qa/standalone/scrub/osd-scrub-snaps.sh b/ceph/qa/standalone/scrub/osd-scrub-snaps.sh index c46eae292..7c5102e32 100755 --- a/ceph/qa/standalone/scrub/osd-scrub-snaps.sh +++ b/ceph/qa/standalone/scrub/osd-scrub-snaps.sh @@ -30,7 +30,7 @@ function run() { export CEPH_MON="127.0.0.1:7121" # git grep '\<7121\>' : there must be only one export CEPH_ARGS CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " - CEPH_ARGS+="--mon-host=$CEPH_MON " + CEPH_ARGS+="--mon-host=$CEPH_MON --osd-objectstore=filestore" local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} for func in $funcs ; do diff --git a/ceph/qa/standalone/special/ceph_objectstore_tool.py b/ceph/qa/standalone/special/ceph_objectstore_tool.py index 1bde02b76..06053b9f7 100755 --- a/ceph/qa/standalone/special/ceph_objectstore_tool.py +++ b/ceph/qa/standalone/special/ceph_objectstore_tool.py @@ -1027,7 +1027,7 @@ def main(argv): # Specify a bad --op command cmd = (CFSD_PREFIX + "--op oops").format(osd=ONEOSD) - ERRORS += test_failure(cmd, "Must provide --op (info, log, remove, mkfs, fsck, repair, export, export-remove, import, list, fix-lost, list-pgs, rm-past-intervals, dump-journal, dump-super, meta-list, get-osdmap, set-osdmap, get-inc-osdmap, set-inc-osdmap, mark-complete, dump-import, trim-pg-log)") + ERRORS += test_failure(cmd, "Must provide --op (info, log, remove, mkfs, fsck, repair, export, export-remove, import, list, fix-lost, list-pgs, rm-past-intervals, dump-journal, dump-super, meta-list, get-osdmap, set-osdmap, get-inc-osdmap, set-inc-osdmap, mark-complete, dump-export, trim-pg-log)") # Provide just the object param not a command cmd = (CFSD_PREFIX + "object").format(osd=ONEOSD) @@ -1742,6 +1742,27 @@ def main(argv): ERRORS += EXP_ERRORS + print("Test clear-data-digest") + for nspace in db.keys(): + for basename in db[nspace].keys(): + JSON = db[nspace][basename]['json'] + cmd = (CFSD_PREFIX + "'{json}' clear-data-digest").format(osd='osd0', json=JSON) + logging.debug(cmd) + ret = call(cmd, shell=True, stdout=nullfd, stderr=nullfd) + if ret != 0: + logging.error("Clearing data digest failed for {json}".format(json=JSON)) + ERRORS += 1 + break + cmd = (CFSD_PREFIX + "'{json}' dump | grep '\"data_digest\": \"0xff'").format(osd='osd0', json=JSON) + logging.debug(cmd) + ret = call(cmd, shell=True, stdout=nullfd, stderr=nullfd) + if ret != 0: + logging.error("Data digest not cleared for {json}".format(json=JSON)) + ERRORS += 1 + break + break + break + print("Test pg removal") RM_ERRORS = 0 for pg in ALLREPPGS + ALLECPGS: @@ -1771,11 +1792,11 @@ def main(argv): for pg in PGS: file = os.path.join(dir, pg) # Make sure this doesn't crash - cmd = (CFSD_PREFIX + "--op dump-import --file {file}").format(osd=osd, file=file) + cmd = (CFSD_PREFIX + "--op dump-export --file {file}").format(osd=osd, file=file) logging.debug(cmd) ret = call(cmd, shell=True, stdout=nullfd) if ret != 0: - logging.error("Dump-import failed from {file} with {ret}".format(file=file, ret=ret)) + logging.error("Dump-export failed from {file} with {ret}".format(file=file, ret=ret)) IMP_ERRORS += 1 # This should do nothing cmd = (CFSD_PREFIX + "--op import --file {file} --dry-run").format(osd=osd, file=file) diff --git a/ceph/qa/suites/big/.qa b/ceph/qa/suites/big/.qa index a602a0353..4d575fee9 120000 --- a/ceph/qa/suites/big/.qa +++ b/ceph/qa/suites/big/.qa @@ -1 +1 @@ -../.qa/ \ No newline at end of file +../../../../.qa/ \ No newline at end of file diff --git a/ceph/qa/suites/ceph-disk/basic/distros b/ceph/qa/suites/ceph-disk/basic/distros index c5d59352c..23d9e9be8 120000 --- a/ceph/qa/suites/ceph-disk/basic/distros +++ b/ceph/qa/suites/ceph-disk/basic/distros @@ -1 +1 @@ -../../../distros/supported \ No newline at end of file +.qa/distros/supported \ No newline at end of file diff --git a/ceph/qa/suites/fs/bugs/conf b/ceph/qa/suites/fs/bugs/client_trim_caps/conf similarity index 100% rename from ceph/qa/suites/fs/bugs/conf rename to ceph/qa/suites/fs/bugs/client_trim_caps/conf diff --git a/ceph/qa/suites/fs/multiclient/tasks/ior-shared-file.yaml b/ceph/qa/suites/fs/multiclient/tasks/ior-shared-file.yaml index 94501b2ae..4e0c307f3 100644 --- a/ceph/qa/suites/fs/multiclient/tasks/ior-shared-file.yaml +++ b/ceph/qa/suites/fs/multiclient/tasks/ior-shared-file.yaml @@ -1,6 +1,6 @@ # make sure we get the same MPI version on all hosts os_type: ubuntu -os_version: "14.04" +os_version: "16.04" tasks: - pexec: diff --git a/ceph/qa/suites/fs/multiclient/tasks/mdtest.yaml b/ceph/qa/suites/fs/multiclient/tasks/mdtest.yaml index fd337bd67..52f2eab83 100644 --- a/ceph/qa/suites/fs/multiclient/tasks/mdtest.yaml +++ b/ceph/qa/suites/fs/multiclient/tasks/mdtest.yaml @@ -1,6 +1,6 @@ # make sure we get the same MPI version on all hosts os_type: ubuntu -os_version: "14.04" +os_version: "16.04" tasks: - pexec: diff --git a/ceph/qa/suites/fs/thrash/msgr-failures/osd-mds-delay.yaml b/ceph/qa/suites/fs/thrash/msgr-failures/osd-mds-delay.yaml index 4dc0086e6..688029619 100644 --- a/ceph/qa/suites/fs/thrash/msgr-failures/osd-mds-delay.yaml +++ b/ceph/qa/suites/fs/thrash/msgr-failures/osd-mds-delay.yaml @@ -6,3 +6,5 @@ overrides: ms inject delay type: osd mds ms inject delay probability: .005 ms inject delay max: 1 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/hadoop/basic/clusters/fixed-3.yaml b/ceph/qa/suites/hadoop/basic/clusters/fixed-3.yaml deleted file mode 100644 index 6fc0af68f..000000000 --- a/ceph/qa/suites/hadoop/basic/clusters/fixed-3.yaml +++ /dev/null @@ -1,17 +0,0 @@ - -os_type: ubuntu -os_version: "14.04" - -overrides: - ceph: - conf: - client: - client permissions: false -roles: -- [mon.0, mds.0, osd.0, hadoop.master.0] -- [mon.1, mgr.x, osd.1, hadoop.slave.0] -- [mon.2, mgr.y, hadoop.slave.1, client.0] -openstack: -- volumes: # attached to each instance - count: 1 - size: 10 # GB diff --git a/ceph/qa/suites/hadoop/basic/filestore-xfs.yaml b/ceph/qa/suites/hadoop/basic/filestore-xfs.yaml deleted file mode 120000 index 59ef7e484..000000000 --- a/ceph/qa/suites/hadoop/basic/filestore-xfs.yaml +++ /dev/null @@ -1 +0,0 @@ -../../../objectstore/filestore-xfs.yaml \ No newline at end of file diff --git a/ceph/qa/suites/hadoop/basic/tasks/repl.yaml b/ceph/qa/suites/hadoop/basic/tasks/repl.yaml deleted file mode 100644 index 60cdcca32..000000000 --- a/ceph/qa/suites/hadoop/basic/tasks/repl.yaml +++ /dev/null @@ -1,8 +0,0 @@ -tasks: -- ssh_keys: -- install: -- ceph: -- hadoop: -- workunit: - clients: - client.0: [hadoop/repl.sh] diff --git a/ceph/qa/suites/hadoop/basic/tasks/terasort.yaml b/ceph/qa/suites/hadoop/basic/tasks/terasort.yaml deleted file mode 100644 index 4377894f5..000000000 --- a/ceph/qa/suites/hadoop/basic/tasks/terasort.yaml +++ /dev/null @@ -1,10 +0,0 @@ -tasks: -- ssh_keys: -- install: -- ceph: -- hadoop: -- workunit: - clients: - client.0: [hadoop/terasort.sh] - env: - NUM_RECORDS: "10000000" diff --git a/ceph/qa/suites/hadoop/basic/tasks/wordcount.yaml b/ceph/qa/suites/hadoop/basic/tasks/wordcount.yaml deleted file mode 100644 index b84941b81..000000000 --- a/ceph/qa/suites/hadoop/basic/tasks/wordcount.yaml +++ /dev/null @@ -1,8 +0,0 @@ -tasks: -- ssh_keys: -- install: -- ceph: -- hadoop: -- workunit: - clients: - client.0: [hadoop/wordcount.sh] diff --git a/ceph/qa/suites/kcephfs/cephfs/begin.yaml b/ceph/qa/suites/kcephfs/cephfs/begin.yaml new file mode 120000 index 000000000..311d404f7 --- /dev/null +++ b/ceph/qa/suites/kcephfs/cephfs/begin.yaml @@ -0,0 +1 @@ +.qa/cephfs/begin.yaml \ No newline at end of file diff --git a/ceph/qa/suites/kcephfs/cephfs/inline/no.yaml b/ceph/qa/suites/kcephfs/cephfs/inline/no.yaml index 2030acb90..e69de29bb 100644 --- a/ceph/qa/suites/kcephfs/cephfs/inline/no.yaml +++ b/ceph/qa/suites/kcephfs/cephfs/inline/no.yaml @@ -1,3 +0,0 @@ -tasks: -- install: -- ceph: diff --git a/ceph/qa/suites/kcephfs/cephfs/inline/yes.yaml b/ceph/qa/suites/kcephfs/cephfs/inline/yes.yaml index fce64c6c1..ae5222f6b 100644 --- a/ceph/qa/suites/kcephfs/cephfs/inline/yes.yaml +++ b/ceph/qa/suites/kcephfs/cephfs/inline/yes.yaml @@ -1,6 +1,4 @@ tasks: -- install: -- ceph: - exec: client.0: - sudo ceph mds set inline_data true --yes-i-really-mean-it diff --git a/ceph/qa/suites/kcephfs/mixed-clients/begin.yaml b/ceph/qa/suites/kcephfs/mixed-clients/begin.yaml new file mode 120000 index 000000000..311d404f7 --- /dev/null +++ b/ceph/qa/suites/kcephfs/mixed-clients/begin.yaml @@ -0,0 +1 @@ +.qa/cephfs/begin.yaml \ No newline at end of file diff --git a/ceph/qa/suites/kcephfs/mixed-clients/tasks/kernel_cfuse_workunits_dbench_iozone.yaml b/ceph/qa/suites/kcephfs/mixed-clients/tasks/kernel_cfuse_workunits_dbench_iozone.yaml index 0121a01c5..78b2d7611 100644 --- a/ceph/qa/suites/kcephfs/mixed-clients/tasks/kernel_cfuse_workunits_dbench_iozone.yaml +++ b/ceph/qa/suites/kcephfs/mixed-clients/tasks/kernel_cfuse_workunits_dbench_iozone.yaml @@ -1,6 +1,4 @@ tasks: -- install: -- ceph: - parallel: - user-workload - kclient-workload diff --git a/ceph/qa/suites/kcephfs/mixed-clients/tasks/kernel_cfuse_workunits_untarbuild_blogbench.yaml b/ceph/qa/suites/kcephfs/mixed-clients/tasks/kernel_cfuse_workunits_untarbuild_blogbench.yaml index 7b0ce5b5d..d637ff989 100644 --- a/ceph/qa/suites/kcephfs/mixed-clients/tasks/kernel_cfuse_workunits_untarbuild_blogbench.yaml +++ b/ceph/qa/suites/kcephfs/mixed-clients/tasks/kernel_cfuse_workunits_untarbuild_blogbench.yaml @@ -1,6 +1,4 @@ tasks: -- install: -- ceph: - parallel: - user-workload - kclient-workload diff --git a/ceph/qa/suites/kcephfs/recovery/begin.yaml b/ceph/qa/suites/kcephfs/recovery/begin.yaml new file mode 120000 index 000000000..311d404f7 --- /dev/null +++ b/ceph/qa/suites/kcephfs/recovery/begin.yaml @@ -0,0 +1 @@ +.qa/cephfs/begin.yaml \ No newline at end of file diff --git a/ceph/qa/suites/kcephfs/recovery/mounts/kmounts.yaml b/ceph/qa/suites/kcephfs/recovery/mounts/kmounts.yaml index c18db8f5e..c9a1f5b6f 100644 --- a/ceph/qa/suites/kcephfs/recovery/mounts/kmounts.yaml +++ b/ceph/qa/suites/kcephfs/recovery/mounts/kmounts.yaml @@ -1,4 +1,2 @@ tasks: -- install: -- ceph: - kclient: diff --git a/ceph/qa/suites/kcephfs/thrash/begin.yaml b/ceph/qa/suites/kcephfs/thrash/begin.yaml new file mode 120000 index 000000000..311d404f7 --- /dev/null +++ b/ceph/qa/suites/kcephfs/thrash/begin.yaml @@ -0,0 +1 @@ +.qa/cephfs/begin.yaml \ No newline at end of file diff --git a/ceph/qa/suites/kcephfs/thrash/thrashers/default.yaml b/ceph/qa/suites/kcephfs/thrash/thrashers/default.yaml index e628ba6da..1829619bd 100644 --- a/ceph/qa/suites/kcephfs/thrash/thrashers/default.yaml +++ b/ceph/qa/suites/kcephfs/thrash/thrashers/default.yaml @@ -1,7 +1,7 @@ -tasks: -- install: -- ceph: +overrides: + ceph: log-whitelist: - - but it is still running - - objects unfound and apparently lost + - but it is still running + - objects unfound and apparently lost +tasks: - thrashosds: diff --git a/ceph/qa/suites/kcephfs/thrash/thrashers/mds.yaml b/ceph/qa/suites/kcephfs/thrash/thrashers/mds.yaml index d5d1f4357..ce87575c7 100644 --- a/ceph/qa/suites/kcephfs/thrash/thrashers/mds.yaml +++ b/ceph/qa/suites/kcephfs/thrash/thrashers/mds.yaml @@ -1,9 +1,7 @@ -tasks: -- install: -- ceph: -- mds_thrash: - overrides: ceph: log-whitelist: - not responding, replacing + +tasks: +- mds_thrash: diff --git a/ceph/qa/suites/kcephfs/thrash/thrashers/mon.yaml b/ceph/qa/suites/kcephfs/thrash/thrashers/mon.yaml index aa876d7d4..d72a99cbc 100644 --- a/ceph/qa/suites/kcephfs/thrash/thrashers/mon.yaml +++ b/ceph/qa/suites/kcephfs/thrash/thrashers/mon.yaml @@ -2,9 +2,8 @@ overrides: ceph: log-whitelist: - \(MON_DOWN\) + tasks: -- install: -- ceph: - mon_thrash: revive_delay: 20 thrash_delay: 1 diff --git a/ceph/qa/suites/krbd/rbd-nomount/msgr-failures/few.yaml b/ceph/qa/suites/krbd/rbd-nomount/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/krbd/rbd-nomount/msgr-failures/few.yaml +++ b/ceph/qa/suites/krbd/rbd-nomount/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/krbd/rbd-nomount/msgr-failures/many.yaml b/ceph/qa/suites/krbd/rbd-nomount/msgr-failures/many.yaml index 86f8dde8a..4caedaebd 100644 --- a/ceph/qa/suites/krbd/rbd-nomount/msgr-failures/many.yaml +++ b/ceph/qa/suites/krbd/rbd-nomount/msgr-failures/many.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 500 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/krbd/rbd-nomount/tasks/krbd_udev_enumerate.yaml b/ceph/qa/suites/krbd/rbd-nomount/tasks/krbd_udev_enumerate.yaml new file mode 100644 index 000000000..c326507ac --- /dev/null +++ b/ceph/qa/suites/krbd/rbd-nomount/tasks/krbd_udev_enumerate.yaml @@ -0,0 +1,5 @@ +tasks: +- workunit: + clients: + all: + - rbd/krbd_udev_enumerate.sh diff --git a/ceph/qa/suites/krbd/rbd-nomount/tasks/krbd_udev_netlink_enobufs.yaml b/ceph/qa/suites/krbd/rbd-nomount/tasks/krbd_udev_netlink_enobufs.yaml new file mode 100644 index 000000000..b0530d52c --- /dev/null +++ b/ceph/qa/suites/krbd/rbd-nomount/tasks/krbd_udev_netlink_enobufs.yaml @@ -0,0 +1,10 @@ +overrides: + ceph: + log-whitelist: + - pauserd,pausewr flag\(s\) set + +tasks: +- workunit: + clients: + all: + - rbd/krbd_udev_netlink_enobufs.sh diff --git a/ceph/qa/suites/krbd/rbd/msgr-failures/few.yaml b/ceph/qa/suites/krbd/rbd/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/krbd/rbd/msgr-failures/few.yaml +++ b/ceph/qa/suites/krbd/rbd/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/krbd/rbd/msgr-failures/many.yaml b/ceph/qa/suites/krbd/rbd/msgr-failures/many.yaml index 86f8dde8a..4caedaebd 100644 --- a/ceph/qa/suites/krbd/rbd/msgr-failures/many.yaml +++ b/ceph/qa/suites/krbd/rbd/msgr-failures/many.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 500 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/krbd/singleton/msgr-failures/few.yaml b/ceph/qa/suites/krbd/singleton/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/krbd/singleton/msgr-failures/few.yaml +++ b/ceph/qa/suites/krbd/singleton/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/krbd/singleton/msgr-failures/many.yaml b/ceph/qa/suites/krbd/singleton/msgr-failures/many.yaml index 86f8dde8a..4caedaebd 100644 --- a/ceph/qa/suites/krbd/singleton/msgr-failures/many.yaml +++ b/ceph/qa/suites/krbd/singleton/msgr-failures/many.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 500 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/krbd/wac/wac/verify/many-resets.yaml b/ceph/qa/suites/krbd/wac/wac/verify/many-resets.yaml index 526897e9c..d69f65031 100644 --- a/ceph/qa/suites/krbd/wac/wac/verify/many-resets.yaml +++ b/ceph/qa/suites/krbd/wac/wac/verify/many-resets.yaml @@ -3,6 +3,8 @@ overrides: conf: global: ms inject socket failures: 500 + log-whitelist: + - \(OSD_SLOW_PING_TIME tasks: - exec: client.0: diff --git a/ceph/qa/suites/powercycle/osd/powercycle/default.yaml b/ceph/qa/suites/powercycle/osd/powercycle/default.yaml index b632e83e6..a693f4b41 100644 --- a/ceph/qa/suites/powercycle/osd/powercycle/default.yaml +++ b/ceph/qa/suites/powercycle/osd/powercycle/default.yaml @@ -1,5 +1,8 @@ tasks: - install: + extra_system_packages: + deb: ['bison', 'flex', 'libelf-dev', 'libssl-dev'] + rpm: ['bison', 'flex', 'elfutils-libelf-devel', 'openssl-devel'] - ceph: - thrashosds: chance_down: 1.0 diff --git a/ceph/qa/suites/rados/basic/msgr-failures/few.yaml b/ceph/qa/suites/rados/basic/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rados/basic/msgr-failures/few.yaml +++ b/ceph/qa/suites/rados/basic/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/basic/msgr-failures/many.yaml b/ceph/qa/suites/rados/basic/msgr-failures/many.yaml index 038c3a799..f4bb065b5 100644 --- a/ceph/qa/suites/rados/basic/msgr-failures/many.yaml +++ b/ceph/qa/suites/rados/basic/msgr-failures/many.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 1500 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/basic/tasks/rgw_snaps.yaml b/ceph/qa/suites/rados/basic/tasks/rgw_snaps.yaml index ec864916d..8281a9f8f 100644 --- a/ceph/qa/suites/rados/basic/tasks/rgw_snaps.yaml +++ b/ceph/qa/suites/rados/basic/tasks/rgw_snaps.yaml @@ -26,6 +26,7 @@ tasks: - default.rgw.log - s3readwrite: client.0: + force-branch: ceph-luminous rgw_server: client.0 readwrite: bucket: rwtest diff --git a/ceph/qa/suites/rados/monthrash/msgr-failures/few.yaml b/ceph/qa/suites/rados/monthrash/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rados/monthrash/msgr-failures/few.yaml +++ b/ceph/qa/suites/rados/monthrash/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/monthrash/msgr-failures/mon-delay.yaml b/ceph/qa/suites/rados/monthrash/msgr-failures/mon-delay.yaml index da25b7a09..fcd8ca7c2 100644 --- a/ceph/qa/suites/rados/monthrash/msgr-failures/mon-delay.yaml +++ b/ceph/qa/suites/rados/monthrash/msgr-failures/mon-delay.yaml @@ -9,3 +9,5 @@ overrides: ms inject internal delays: .002 mgr: debug monc: 10 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/multimon/msgr-failures/few.yaml b/ceph/qa/suites/rados/multimon/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rados/multimon/msgr-failures/few.yaml +++ b/ceph/qa/suites/rados/multimon/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/multimon/msgr-failures/many.yaml b/ceph/qa/suites/rados/multimon/msgr-failures/many.yaml index cff375149..6c591ce8a 100644 --- a/ceph/qa/suites/rados/multimon/msgr-failures/many.yaml +++ b/ceph/qa/suites/rados/multimon/msgr-failures/many.yaml @@ -4,3 +4,5 @@ overrides: global: ms inject socket failures: 500 mon mgr beacon grace: 90 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/objectstore/alloc-hint.yaml b/ceph/qa/suites/rados/objectstore/alloc-hint.yaml index d40143c17..047b02fa0 100644 --- a/ceph/qa/suites/rados/objectstore/alloc-hint.yaml +++ b/ceph/qa/suites/rados/objectstore/alloc-hint.yaml @@ -11,6 +11,7 @@ overrides: conf: osd: filestore xfs extsize: true + osd objectstore: filestore tasks: - install: diff --git a/ceph/qa/suites/rados/objectstore/ceph_objectstore_tool.yaml b/ceph/qa/suites/rados/objectstore/ceph_objectstore_tool.yaml index f3163c96b..042bd0657 100644 --- a/ceph/qa/suites/rados/objectstore/ceph_objectstore_tool.yaml +++ b/ceph/qa/suites/rados/objectstore/ceph_objectstore_tool.yaml @@ -12,6 +12,8 @@ tasks: global: osd max object name len: 460 osd max object namespace len: 64 + osd: + osd objectstore: filestore log-whitelist: - overall HEALTH_ - \(OSDMAP_FLAGS\) diff --git a/ceph/qa/suites/rados/singleton-bluestore/msgr-failures/few.yaml b/ceph/qa/suites/rados/singleton-bluestore/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rados/singleton-bluestore/msgr-failures/few.yaml +++ b/ceph/qa/suites/rados/singleton-bluestore/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/singleton-bluestore/msgr-failures/many.yaml b/ceph/qa/suites/rados/singleton-bluestore/msgr-failures/many.yaml index 86f8dde8a..4caedaebd 100644 --- a/ceph/qa/suites/rados/singleton-bluestore/msgr-failures/many.yaml +++ b/ceph/qa/suites/rados/singleton-bluestore/msgr-failures/many.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 500 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/singleton-nomsgr/all/lazy_omap_stats_output.yaml b/ceph/qa/suites/rados/singleton-nomsgr/all/lazy_omap_stats_output.yaml new file mode 100644 index 000000000..9fbdf0e05 --- /dev/null +++ b/ceph/qa/suites/rados/singleton-nomsgr/all/lazy_omap_stats_output.yaml @@ -0,0 +1,16 @@ +openstack: + - volumes: # attached to each instance + count: 2 + size: 10 # GB +roles: +- [mon.a, mgr.x, osd.0, osd.1, osd.2, client.0] +overrides: + ceph: + log-whitelist: + - \(POOL_APP_NOT_ENABLED\) +tasks: +- install: +- ceph: +- exec: + client.0: + - ceph_test_lazy_omap_stats diff --git a/ceph/qa/suites/rados/singleton/all/thrash-eio.yaml b/ceph/qa/suites/rados/singleton/all/thrash-eio.yaml index f4db6ca18..aeed0de9a 100644 --- a/ceph/qa/suites/rados/singleton/all/thrash-eio.yaml +++ b/ceph/qa/suites/rados/singleton/all/thrash-eio.yaml @@ -31,6 +31,8 @@ tasks: - \(OBJECT_MISPLACED\) - \(OSD_ - slow request + - \(OBJECT_ + - \(TOO_FEW_PGS\) - thrashosds: op_delay: 30 clean_interval: 120 diff --git a/ceph/qa/suites/rados/singleton/msgr-failures/few.yaml b/ceph/qa/suites/rados/singleton/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rados/singleton/msgr-failures/few.yaml +++ b/ceph/qa/suites/rados/singleton/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/singleton/msgr-failures/many.yaml b/ceph/qa/suites/rados/singleton/msgr-failures/many.yaml index 19874dc76..1b861b1b4 100644 --- a/ceph/qa/suites/rados/singleton/msgr-failures/many.yaml +++ b/ceph/qa/suites/rados/singleton/msgr-failures/many.yaml @@ -6,3 +6,5 @@ overrides: mon mgr beacon grace: 90 mgr: debug monc: 10 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/standalone/workloads/mgr.yaml b/ceph/qa/suites/rados/standalone/workloads/mgr.yaml new file mode 100644 index 000000000..997fae865 --- /dev/null +++ b/ceph/qa/suites/rados/standalone/workloads/mgr.yaml @@ -0,0 +1,18 @@ +roles: +- - mon.a + - mgr.x + - osd.0 + - osd.1 + - osd.2 + - client.0 +openstack: + - volumes: # attached to each instance + count: 3 + size: 10 # GB +tasks: +- install: +- workunit: + basedir: qa/standalone + clients: + all: + - mgr diff --git a/ceph/qa/suites/rados/thrash/d-require-luminous/at-mkfs-balancer-upmap.yaml b/ceph/qa/suites/rados/thrash/d-require-luminous/at-mkfs-balancer-upmap.yaml index a1e0afea0..a6a11c4de 100644 --- a/ceph/qa/suites/rados/thrash/d-require-luminous/at-mkfs-balancer-upmap.yaml +++ b/ceph/qa/suites/rados/thrash/d-require-luminous/at-mkfs-balancer-upmap.yaml @@ -7,5 +7,6 @@ tasks: - exec: mon.a: - while ! ceph balancer status ; do sleep 1 ; done + - ceph osd set-require-min-compat-client luminous - ceph balancer mode upmap - ceph balancer on diff --git a/ceph/qa/suites/rados/thrash/msgr-failures/fastclose.yaml b/ceph/qa/suites/rados/thrash/msgr-failures/fastclose.yaml index 77fd730af..02121726e 100644 --- a/ceph/qa/suites/rados/thrash/msgr-failures/fastclose.yaml +++ b/ceph/qa/suites/rados/thrash/msgr-failures/fastclose.yaml @@ -4,3 +4,5 @@ overrides: global: ms inject socket failures: 2500 ms tcp read timeout: 5 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/thrash/msgr-failures/few.yaml b/ceph/qa/suites/rados/thrash/msgr-failures/few.yaml index 477bffe61..527eadb45 100644 --- a/ceph/qa/suites/rados/thrash/msgr-failures/few.yaml +++ b/ceph/qa/suites/rados/thrash/msgr-failures/few.yaml @@ -5,3 +5,5 @@ overrides: ms inject socket failures: 5000 osd: osd heartbeat use min delay socket: true + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/thrash/msgr-failures/osd-delay.yaml b/ceph/qa/suites/rados/thrash/msgr-failures/osd-delay.yaml index a33ba89e1..91c147256 100644 --- a/ceph/qa/suites/rados/thrash/msgr-failures/osd-delay.yaml +++ b/ceph/qa/suites/rados/thrash/msgr-failures/osd-delay.yaml @@ -7,3 +7,5 @@ overrides: ms inject delay probability: .005 ms inject delay max: 1 ms inject internal delays: .002 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/upgrade/jewel-x-singleton/5-workload/rbd_api.yaml b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/5-workload/rbd_api.yaml index 22a5f5750..354ad6896 100644 --- a/ceph/qa/suites/rados/upgrade/jewel-x-singleton/5-workload/rbd_api.yaml +++ b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/5-workload/rbd_api.yaml @@ -8,4 +8,6 @@ split_tasks: clients: client.0: - rbd/test_librbd.sh - - print: "**** done rbd/test_librbd.sh 7-workload" + env: + RBD_FEATURES: "61" + - print: "**** done rbd/test_librbd.sh 5-workload" diff --git a/ceph/qa/suites/rados/upgrade/jewel-x-singleton/8-workload/rgw-swift.yaml b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/8-workload/rgw-swift.yaml index e41f47ad0..4a4b48aeb 100644 --- a/ceph/qa/suites/rados/upgrade/jewel-x-singleton/8-workload/rgw-swift.yaml +++ b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/8-workload/rgw-swift.yaml @@ -7,5 +7,6 @@ tasks: - print: "**** done rgw 9-workload" - swift: client.0: + force-branch: ceph-luminous rgw_server: client.0 - print: "**** done swift 9-workload" diff --git a/ceph/qa/suites/rados/upgrade/jewel-x-singleton/distros/.qa b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/distros/.qa new file mode 120000 index 000000000..fea2489fd --- /dev/null +++ b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/distros/.qa @@ -0,0 +1 @@ +../.qa \ No newline at end of file diff --git a/ceph/qa/suites/rados/upgrade/jewel-x-singleton/distros/centos_latest.yaml b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/distros/centos_latest.yaml new file mode 120000 index 000000000..bd9854e70 --- /dev/null +++ b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/distros/centos_latest.yaml @@ -0,0 +1 @@ +.qa/distros/supported/centos_latest.yaml \ No newline at end of file diff --git a/ceph/qa/suites/rados/upgrade/jewel-x-singleton/distros/ubuntu_latest.yaml b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/distros/ubuntu_latest.yaml new file mode 120000 index 000000000..3a09f9abb --- /dev/null +++ b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/distros/ubuntu_latest.yaml @@ -0,0 +1 @@ +.qa/distros/supported/ubuntu_latest.yaml \ No newline at end of file diff --git a/ceph/qa/suites/rados/verify/msgr-failures/few.yaml b/ceph/qa/suites/rados/verify/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rados/verify/msgr-failures/few.yaml +++ b/ceph/qa/suites/rados/verify/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rados/verify/tasks/rados_api_tests.yaml b/ceph/qa/suites/rados/verify/tasks/rados_api_tests.yaml index 9fd048c91..240153fb1 100644 --- a/ceph/qa/suites/rados/verify/tasks/rados_api_tests.yaml +++ b/ceph/qa/suites/rados/verify/tasks/rados_api_tests.yaml @@ -11,6 +11,7 @@ overrides: - \(POOL_APP_NOT_ENABLED\) - \(PG_AVAILABILITY\) - slow request + - \(OBJECT_MISPLACED\) conf: client: debug ms: 1 diff --git a/ceph/qa/suites/rbd/basic/msgr-failures/few.yaml b/ceph/qa/suites/rbd/basic/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rbd/basic/msgr-failures/few.yaml +++ b/ceph/qa/suites/rbd/basic/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rbd/cli/msgr-failures/few.yaml b/ceph/qa/suites/rbd/cli/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rbd/cli/msgr-failures/few.yaml +++ b/ceph/qa/suites/rbd/cli/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rbd/cli/msgr-failures/many.yaml b/ceph/qa/suites/rbd/cli/msgr-failures/many.yaml index 86f8dde8a..4caedaebd 100644 --- a/ceph/qa/suites/rbd/cli/msgr-failures/many.yaml +++ b/ceph/qa/suites/rbd/cli/msgr-failures/many.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 500 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rbd/librbd/msgr-failures/few.yaml b/ceph/qa/suites/rbd/librbd/msgr-failures/few.yaml index 55b6df536..9349b4f9a 100644 --- a/ceph/qa/suites/rbd/librbd/msgr-failures/few.yaml +++ b/ceph/qa/suites/rbd/librbd/msgr-failures/few.yaml @@ -5,3 +5,4 @@ overrides: ms inject socket failures: 5000 log-whitelist: - but it is still running + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rbd/qemu/msgr-failures/few.yaml b/ceph/qa/suites/rbd/qemu/msgr-failures/few.yaml index 55b6df536..9349b4f9a 100644 --- a/ceph/qa/suites/rbd/qemu/msgr-failures/few.yaml +++ b/ceph/qa/suites/rbd/qemu/msgr-failures/few.yaml @@ -5,3 +5,4 @@ overrides: ms inject socket failures: 5000 log-whitelist: - but it is still running + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rbd/thrash/msgr-failures/few.yaml b/ceph/qa/suites/rbd/thrash/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rbd/thrash/msgr-failures/few.yaml +++ b/ceph/qa/suites/rbd/thrash/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rgw/multifs/tasks/rgw_readwrite.yaml b/ceph/qa/suites/rgw/multifs/tasks/rgw_readwrite.yaml index c7efaa1c7..b1fc54839 100644 --- a/ceph/qa/suites/rgw/multifs/tasks/rgw_readwrite.yaml +++ b/ceph/qa/suites/rgw/multifs/tasks/rgw_readwrite.yaml @@ -4,6 +4,7 @@ tasks: - rgw: [client.0] - s3readwrite: client.0: + force-branch: ceph-luminous rgw_server: client.0 readwrite: bucket: rwtest diff --git a/ceph/qa/suites/rgw/multifs/tasks/rgw_roundtrip.yaml b/ceph/qa/suites/rgw/multifs/tasks/rgw_roundtrip.yaml index 47b3c1894..1c5d11cbf 100644 --- a/ceph/qa/suites/rgw/multifs/tasks/rgw_roundtrip.yaml +++ b/ceph/qa/suites/rgw/multifs/tasks/rgw_roundtrip.yaml @@ -4,6 +4,7 @@ tasks: - rgw: [client.0] - s3roundtrip: client.0: + force-branch: ceph-luminous rgw_server: client.0 roundtrip: bucket: rttest diff --git a/ceph/qa/suites/rgw/multifs/tasks/rgw_swift.yaml b/ceph/qa/suites/rgw/multifs/tasks/rgw_swift.yaml index 569741b0e..4451d152c 100644 --- a/ceph/qa/suites/rgw/multifs/tasks/rgw_swift.yaml +++ b/ceph/qa/suites/rgw/multifs/tasks/rgw_swift.yaml @@ -4,4 +4,5 @@ tasks: - rgw: [client.0] - swift: client.0: + force-branch: ceph-luminous rgw_server: client.0 diff --git a/ceph/qa/suites/rgw/tempest/frontend b/ceph/qa/suites/rgw/tempest/frontend deleted file mode 120000 index f67cecad0..000000000 --- a/ceph/qa/suites/rgw/tempest/frontend +++ /dev/null @@ -1 +0,0 @@ -../../../rgw_frontend \ No newline at end of file diff --git a/ceph/qa/suites/rgw/thrash/workload/rgw_readwrite.yaml b/ceph/qa/suites/rgw/thrash/workload/rgw_readwrite.yaml index e4e682868..d2c4fb190 100644 --- a/ceph/qa/suites/rgw/thrash/workload/rgw_readwrite.yaml +++ b/ceph/qa/suites/rgw/thrash/workload/rgw_readwrite.yaml @@ -1,6 +1,7 @@ tasks: - s3readwrite: client.0: + force-branch: ceph-luminous rgw_server: client.0 readwrite: bucket: rwtest diff --git a/ceph/qa/suites/rgw/thrash/workload/rgw_roundtrip.yaml b/ceph/qa/suites/rgw/thrash/workload/rgw_roundtrip.yaml index 621683aeb..f10baca47 100644 --- a/ceph/qa/suites/rgw/thrash/workload/rgw_roundtrip.yaml +++ b/ceph/qa/suites/rgw/thrash/workload/rgw_roundtrip.yaml @@ -1,6 +1,7 @@ tasks: - s3roundtrip: client.0: + force-branch: ceph-luminous rgw_server: client.0 roundtrip: bucket: rttest diff --git a/ceph/qa/suites/rgw/thrash/workload/rgw_swift.yaml b/ceph/qa/suites/rgw/thrash/workload/rgw_swift.yaml index 45e2fc9cc..61041c648 100644 --- a/ceph/qa/suites/rgw/thrash/workload/rgw_swift.yaml +++ b/ceph/qa/suites/rgw/thrash/workload/rgw_swift.yaml @@ -1,4 +1,5 @@ tasks: - swift: client.0: + force-branch: ceph-luminous rgw_server: client.0 diff --git a/ceph/qa/suites/rgw/verify/msgr-failures/few.yaml b/ceph/qa/suites/rgw/verify/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/rgw/verify/msgr-failures/few.yaml +++ b/ceph/qa/suites/rgw/verify/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/rgw/verify/tasks/swift.yaml b/ceph/qa/suites/rgw/verify/tasks/swift.yaml index 45e2fc9cc..61041c648 100644 --- a/ceph/qa/suites/rgw/verify/tasks/swift.yaml +++ b/ceph/qa/suites/rgw/verify/tasks/swift.yaml @@ -1,4 +1,5 @@ tasks: - swift: client.0: + force-branch: ceph-luminous rgw_server: client.0 diff --git a/ceph/qa/suites/smoke/basic/tasks/mon_thrash.yaml b/ceph/qa/suites/smoke/basic/tasks/mon_thrash.yaml index 591931d9f..cec65bef1 100644 --- a/ceph/qa/suites/smoke/basic/tasks/mon_thrash.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/mon_thrash.yaml @@ -3,6 +3,18 @@ overrides: log-whitelist: - reached quota - \(POOL_APP_NOT_ENABLED\) + - \(OSD_SLOW_PING_TIME + - mons down + - overall HEALTH_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(POOL_ + - \(CACHE_POOL_ + - \(SMALLER_PGP_NUM\) + - \(OBJECT_ + - \(REQUEST_SLOW\) + - \(TOO_FEW_PGS\) conf: global: ms inject delay max: 1 diff --git a/ceph/qa/suites/smoke/basic/tasks/rados_api_tests.yaml b/ceph/qa/suites/smoke/basic/tasks/rados_api_tests.yaml index df28ed6a2..3bfa6156a 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rados_api_tests.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rados_api_tests.yaml @@ -3,6 +3,16 @@ tasks: - ceph: fs: ext4 log-whitelist: + - overall HEALTH_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(POOL_ + - \(CACHE_POOL_ + - \(SMALLER_PGP_NUM\) + - \(OBJECT_ + - \(REQUEST_SLOW\) + - \(TOO_FEW_PGS\) - reached quota - but it is still running - objects unfound and apparently lost diff --git a/ceph/qa/suites/smoke/basic/tasks/rados_bench.yaml b/ceph/qa/suites/smoke/basic/tasks/rados_bench.yaml index f46ffb9bb..63ab90891 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rados_bench.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rados_bench.yaml @@ -14,6 +14,17 @@ tasks: log-whitelist: - but it is still running - objects unfound and apparently lost + - \(OSD_SLOW_PING_TIME + - overall HEALTH_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(POOL_ + - \(CACHE_POOL_ + - \(SMALLER_PGP_NUM\) + - \(OBJECT_ + - \(REQUEST_SLOW\) + - \(TOO_FEW_PGS\) - thrashosds: chance_pgnum_grow: 2 chance_pgpnum_fix: 1 diff --git a/ceph/qa/suites/smoke/basic/tasks/rados_cache_snaps.yaml b/ceph/qa/suites/smoke/basic/tasks/rados_cache_snaps.yaml index e7d9e89f7..8b14092d5 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rados_cache_snaps.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rados_cache_snaps.yaml @@ -2,8 +2,16 @@ tasks: - install: null - ceph: log-whitelist: - - but it is still running - - objects unfound and apparently lost + - overall HEALTH_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(POOL_ + - \(CACHE_POOL_ + - \(SMALLER_PGP_NUM\) + - \(OBJECT_ + - \(REQUEST_SLOW\) + - \(TOO_FEW_PGS\) - thrashosds: chance_pgnum_grow: 2 chance_pgpnum_fix: 1 diff --git a/ceph/qa/suites/smoke/basic/tasks/rados_cls_all.yaml b/ceph/qa/suites/smoke/basic/tasks/rados_cls_all.yaml index 7f18a7e95..a3e4980df 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rados_cls_all.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rados_cls_all.yaml @@ -1,3 +1,11 @@ +overrides: + ceph: + conf: + osd: + osd_class_load_list: "cephfs hello journal lock log numops rbd refcount + replica_log rgw sdk statelog timeindex user version" + osd_class_default_list: "cephfs hello journal lock log numops rbd refcount + replica_log rgw sdk statelog timeindex user version" tasks: - install: - ceph: diff --git a/ceph/qa/suites/smoke/basic/tasks/rados_ec_snaps.yaml b/ceph/qa/suites/smoke/basic/tasks/rados_ec_snaps.yaml index a2e23ae60..c83d08b4e 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rados_ec_snaps.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rados_ec_snaps.yaml @@ -3,8 +3,16 @@ tasks: - ceph: fs: xfs log-whitelist: - - but it is still running - - objects unfound and apparently lost + - overall HEALTH_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(POOL_ + - \(CACHE_POOL_ + - \(SMALLER_PGP_NUM\) + - \(OBJECT_ + - \(REQUEST_SLOW\) + - \(TOO_FEW_PGS\) - thrashosds: chance_pgnum_grow: 3 chance_pgpnum_fix: 1 diff --git a/ceph/qa/suites/smoke/basic/tasks/rados_python.yaml b/ceph/qa/suites/smoke/basic/tasks/rados_python.yaml index c6d2ceea3..2a802cd63 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rados_python.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rados_python.yaml @@ -2,7 +2,13 @@ tasks: - install: - ceph: log-whitelist: - - but it is still running + - but it is still running + - overall HEALTH_ + - \(OSDMAP_FLAGS\) + - \(PG_ + - \(OSD_ + - \(OBJECT_ + - \(POOL_APP_NOT_ENABLED\) - ceph-fuse: - workunit: clients: diff --git a/ceph/qa/suites/smoke/basic/tasks/rados_workunit_loadgen_mix.yaml b/ceph/qa/suites/smoke/basic/tasks/rados_workunit_loadgen_mix.yaml index 0d472a33b..5e82e9842 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rados_workunit_loadgen_mix.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rados_workunit_loadgen_mix.yaml @@ -2,6 +2,10 @@ tasks: - install: - ceph: fs: ext4 + log-whitelist: + - but it is still running + - overall HEALTH_ + - \(POOL_APP_NOT_ENABLED\) - ceph-fuse: - workunit: clients: diff --git a/ceph/qa/suites/smoke/basic/tasks/rbd_api_tests.yaml b/ceph/qa/suites/smoke/basic/tasks/rbd_api_tests.yaml index a0dda21a5..f7245bab6 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rbd_api_tests.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rbd_api_tests.yaml @@ -1,6 +1,13 @@ tasks: - install: - ceph: + log-whitelist: + - overall HEALTH_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(POOL_ + - \(CACHE_POOL_ fs: xfs - ceph-fuse: - workunit: diff --git a/ceph/qa/suites/smoke/basic/tasks/rbd_fsx.yaml b/ceph/qa/suites/smoke/basic/tasks/rbd_fsx.yaml index ed737a333..d6da076e7 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rbd_fsx.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rbd_fsx.yaml @@ -1,5 +1,17 @@ overrides: ceph: + log-whitelist: + - \(OSD_SLOW_PING_TIME + - overall HEALTH_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(POOL_ + - \(CACHE_POOL_ + - \(SMALLER_PGP_NUM\) + - \(OBJECT_ + - \(REQUEST_SLOW\) + - \(TOO_FEW_PGS\) conf: client: rbd cache: true diff --git a/ceph/qa/suites/smoke/basic/tasks/rgw_ec_s3tests.yaml b/ceph/qa/suites/smoke/basic/tasks/rgw_ec_s3tests.yaml index dc8fb6f54..a64e1f542 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rgw_ec_s3tests.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rgw_ec_s3tests.yaml @@ -9,6 +9,7 @@ tasks: - rgw: [client.0] - s3tests: client.0: + force-branch: ceph-luminous rgw_server: client.0 overrides: ceph: diff --git a/ceph/qa/suites/smoke/basic/tasks/rgw_s3tests.yaml b/ceph/qa/suites/smoke/basic/tasks/rgw_s3tests.yaml index cc83ee379..c02cedfc2 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rgw_s3tests.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rgw_s3tests.yaml @@ -5,6 +5,7 @@ tasks: - rgw: [client.0] - s3tests: client.0: + force-branch: ceph-luminous rgw_server: client.0 overrides: ceph: diff --git a/ceph/qa/suites/smoke/basic/tasks/rgw_swift.yaml b/ceph/qa/suites/smoke/basic/tasks/rgw_swift.yaml index 57c7226e3..9add4c00a 100644 --- a/ceph/qa/suites/smoke/basic/tasks/rgw_swift.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/rgw_swift.yaml @@ -5,4 +5,5 @@ tasks: - rgw: [client.0] - swift: client.0: + force-branch: ceph-luminous rgw_server: client.0 diff --git a/ceph/qa/suites/teuthology/rgw/tasks/s3tests-civetweb.yaml b/ceph/qa/suites/teuthology/rgw/tasks/s3tests-civetweb.yaml index 01580e38f..0b583831f 100644 --- a/ceph/qa/suites/teuthology/rgw/tasks/s3tests-civetweb.yaml +++ b/ceph/qa/suites/teuthology/rgw/tasks/s3tests-civetweb.yaml @@ -11,7 +11,7 @@ tasks: - s3tests: client.0: rgw_server: client.0 - force-branch: master + force-branch: ceph-luminous overrides: ceph: fs: xfs diff --git a/ceph/qa/suites/teuthology/rgw/tasks/s3tests-fastcgi.yaml b/ceph/qa/suites/teuthology/rgw/tasks/s3tests-fastcgi.yaml index d8a505038..674dc3c81 100644 --- a/ceph/qa/suites/teuthology/rgw/tasks/s3tests-fastcgi.yaml +++ b/ceph/qa/suites/teuthology/rgw/tasks/s3tests-fastcgi.yaml @@ -11,7 +11,7 @@ tasks: - s3tests: client.0: rgw_server: client.0 - force-branch: master + force-branch: ceph-luminous overrides: ceph: fs: xfs diff --git a/ceph/qa/suites/teuthology/rgw/tasks/s3tests-fcgi.yaml b/ceph/qa/suites/teuthology/rgw/tasks/s3tests-fcgi.yaml index 1def7b042..707ca2495 100644 --- a/ceph/qa/suites/teuthology/rgw/tasks/s3tests-fcgi.yaml +++ b/ceph/qa/suites/teuthology/rgw/tasks/s3tests-fcgi.yaml @@ -12,7 +12,7 @@ tasks: - s3tests: client.0: rgw_server: client.0 - force-branch: master + force-branch: ceph-luminous overrides: ceph: fs: xfs diff --git a/ceph/qa/suites/tgt/basic/msgr-failures/few.yaml b/ceph/qa/suites/tgt/basic/msgr-failures/few.yaml index 0de320d46..4326fe23e 100644 --- a/ceph/qa/suites/tgt/basic/msgr-failures/few.yaml +++ b/ceph/qa/suites/tgt/basic/msgr-failures/few.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 5000 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/tgt/basic/msgr-failures/many.yaml b/ceph/qa/suites/tgt/basic/msgr-failures/many.yaml index 86f8dde8a..4caedaebd 100644 --- a/ceph/qa/suites/tgt/basic/msgr-failures/many.yaml +++ b/ceph/qa/suites/tgt/basic/msgr-failures/many.yaml @@ -3,3 +3,5 @@ overrides: conf: global: ms inject socket failures: 500 + log-whitelist: + - \(OSD_SLOW_PING_TIME diff --git a/ceph/qa/suites/hadoop/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/.qa similarity index 100% rename from ceph/qa/suites/hadoop/.qa rename to ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/.qa diff --git a/ceph/qa/suites/hadoop/basic/% b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/% similarity index 100% rename from ceph/qa/suites/hadoop/basic/% rename to ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/% diff --git a/ceph/qa/suites/hadoop/basic/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/.qa similarity index 100% rename from ceph/qa/suites/hadoop/basic/.qa rename to ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/.qa diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/+ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/+ new file mode 100644 index 000000000..e69de29bb diff --git a/ceph/qa/suites/hadoop/basic/clusters/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/.qa similarity index 100% rename from ceph/qa/suites/hadoop/basic/clusters/.qa rename to ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/.qa diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/openstack.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/openstack.yaml new file mode 100644 index 000000000..b0f3b9b4d --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/openstack.yaml @@ -0,0 +1,4 @@ +openstack: + - volumes: # attached to each instance + count: 4 + size: 30 # GB diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/start.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/start.yaml new file mode 100644 index 000000000..624f69d93 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/0-cluster/start.yaml @@ -0,0 +1,17 @@ +roles: +- - mon.a + - mon.b + - mon.c + - osd.0 + - osd.1 + - osd.2 + - mgr.x +- - client.0 +overrides: + ceph: + log-whitelist: + - failed to encode map + - CACHE_POOL_NO_HIT_SET + - POOL_APP_NOT_ENABLED + - application not enabled + fs: xfs diff --git a/ceph/qa/suites/hadoop/basic/tasks/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/1-install/.qa similarity index 100% rename from ceph/qa/suites/hadoop/basic/tasks/.qa rename to ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/1-install/.qa diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/1-install/luminous-client-x.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/1-install/luminous-client-x.yaml new file mode 100644 index 000000000..56137a9a5 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/1-install/luminous-client-x.yaml @@ -0,0 +1,11 @@ +tasks: +- install: + branch: luminous + exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev','python34-cephfs','python34-rados'] +- print: "**** done install luminous" +upgrade_workload: + sequential: + - install.upgrade: + exclude_packages: ['ceph-test', 'ceph-test-dbg','libcephfs1'] + client.0: + - print: "**** done install.upgrade to -x on client.0" diff --git a/ceph/qa/suites/rgw/tempest/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/2-workload/.qa similarity index 100% rename from ceph/qa/suites/rgw/tempest/.qa rename to ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/2-workload/.qa diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/2-workload/devstack-tempest-gate.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/2-workload/devstack-tempest-gate.yaml new file mode 100644 index 000000000..cb9ce29c1 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/2-workload/devstack-tempest-gate.yaml @@ -0,0 +1,56 @@ +tasks: +- sequential: + - upgrade_workload +- ceph: +- print: "**** done ceph" +- qemu: + client.0: + type: filesystem + cpus: 4 + memory: 12288 + disks: + - image_size: 30720 + - image_size: 30720 + test: qa/workunits/rbd/run_devstack_tempest.sh + image_url: https://cloud-images.ubuntu.com/releases/16.04/release/ubuntu-16.04-server-cloudimg-amd64-disk1.img + cloud_config_archive: + - type: text/cloud-config + content: | + users: + - name: stack + lock_passwd: False + shell: /bin/bash + sudo: ["ALL=(root) NOPASSWD:ALL\nDefaults:stack,tempest !requiretty"] + - name: tempest + lock_passwd: False + shell: /bin/bash + sudo: + - "ALL=(root) NOPASSWD:/sbin/ip" + - "ALL=(root) NOPASSWD:/sbin/iptables" + - "ALL=(root) NOPASSWD:/usr/bin/ovsdb-client" + - | + #!/bin/bash -ex + wget -q -O- "http://git.ceph.com/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc" | apt-key add - + wget -q -O /etc/apt/sources.list.d/ceph.list "https://shaman.ceph.com/api/repos/ceph/{ceph_branch}/{ceph_sha1}/ubuntu/xenial/repo" + apt-get update + + mount --bind /mnt/test_b /opt + mkdir /opt/stack + chown -R stack:stack /home/stack + chown -R stack:stack /opt/stack + + mkdir /mnt/log/stack + chmod a+rwx /mnt/log/stack + chown -R stack:stack /mnt/log/stack + + apt-get install -y ceph-common librbd1 + + mkdir /mnt/log/stack/ceph + chown -R stack:stack /mnt/log/stack/ceph + chmod a+rwx /mnt/log/stack/ceph + + # sanity check that the cluster is reachable from the VM + echo '[client]' >> /etc/ceph/ceph.conf + echo 'log file = /mnt/log/stack/ceph/$name.$pid.log' >> /etc/ceph/ceph.conf + rbd --debug-ms=10 --debug-rbd=20 info client.0.1 +- print: "**** done qemu task!" diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/.qa new file mode 120000 index 000000000..4d575fee9 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/.qa @@ -0,0 +1 @@ +../../../../.qa/ \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/centos_7.6.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/centos_7.6.yaml new file mode 120000 index 000000000..c336cfc6a --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/centos_7.6.yaml @@ -0,0 +1 @@ +../../../../../../distros/all/centos_7.6.yaml \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/rhel_7.6.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/rhel_7.6.yaml new file mode 120000 index 000000000..4fd43cc0d --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/rhel_7.6.yaml @@ -0,0 +1 @@ +../../../../../../distros/all/rhel_7.6.yaml \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/ubuntu_16.04.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/ubuntu_16.04.yaml new file mode 120000 index 000000000..9dc1ea992 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/basic/supported/ubuntu_16.04.yaml @@ -0,0 +1 @@ +../../../../../../distros/all/ubuntu_16.04.yaml \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/% b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/% new file mode 100644 index 000000000..e69de29bb diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/.qa new file mode 120000 index 000000000..a602a0353 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/.qa @@ -0,0 +1 @@ +../.qa/ \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/+ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/+ new file mode 100644 index 000000000..e69de29bb diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/.qa new file mode 120000 index 000000000..a602a0353 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/.qa @@ -0,0 +1 @@ +../.qa/ \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/openstack.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/openstack.yaml new file mode 100644 index 000000000..b0f3b9b4d --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/openstack.yaml @@ -0,0 +1,4 @@ +openstack: + - volumes: # attached to each instance + count: 4 + size: 30 # GB diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/start.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/start.yaml new file mode 100644 index 000000000..699811f65 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/0-cluster/start.yaml @@ -0,0 +1,15 @@ +roles: +- - mon.a + - mon.b + - mon.c + - osd.0 + - osd.1 + - osd.2 + - client.0 + - mgr.x +- - client.1 +overrides: + ceph: + log-whitelist: + - failed to encode map + fs: xfs diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/1-install/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/1-install/.qa new file mode 120000 index 000000000..a602a0353 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/1-install/.qa @@ -0,0 +1 @@ +../.qa/ \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/1-install/luminous-client-x.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/1-install/luminous-client-x.yaml new file mode 100644 index 000000000..463bb5c6e --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/1-install/luminous-client-x.yaml @@ -0,0 +1,11 @@ +tasks: +- install: + branch: luminous + exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev','python34-cephfs','python34-rados'] +- print: "**** done install luminous" +- install.upgrade: + exclude_packages: ['ceph-test', 'ceph-test-dbg','libcephfs1'] + client.1: +- print: "**** done install.upgrade to -x on client.0" +- ceph: +- print: "**** done ceph task" diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/2-features/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/2-features/.qa new file mode 120000 index 000000000..a602a0353 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/2-features/.qa @@ -0,0 +1 @@ +../.qa/ \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/2-features/defaults.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/2-features/defaults.yaml new file mode 100644 index 000000000..dff6623ad --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/2-features/defaults.yaml @@ -0,0 +1,6 @@ +overrides: + ceph: + conf: + client: + rbd default features: 61 + diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/2-features/layering.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/2-features/layering.yaml new file mode 100644 index 000000000..5613d0155 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/2-features/layering.yaml @@ -0,0 +1,6 @@ +overrides: + ceph: + conf: + client: + rbd default features: 1 + diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/3-workload/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/3-workload/.qa new file mode 120000 index 000000000..a602a0353 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/3-workload/.qa @@ -0,0 +1 @@ +../.qa/ \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/3-workload/rbd_notification_tests.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/3-workload/rbd_notification_tests.yaml new file mode 100644 index 000000000..17d2c17db --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/3-workload/rbd_notification_tests.yaml @@ -0,0 +1,21 @@ +tasks: +- workunit: + branch: luminous + clients: + client.0: + - rbd/notify_master.sh + client.1: + - rbd/notify_slave.sh + env: + RBD_FEATURES: "61" +- print: "**** done rbd: old librbd -> new librbd" +- workunit: + branch: luminous + clients: + client.0: + - rbd/notify_slave.sh + client.1: + - rbd/notify_master.sh + env: + RBD_FEATURES: "61" +- print: "**** done rbd: new librbd -> old librbd" diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/supported/.qa b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/supported/.qa new file mode 120000 index 000000000..a602a0353 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/supported/.qa @@ -0,0 +1 @@ +../.qa/ \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/supported/ubuntu_16.04.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/supported/ubuntu_16.04.yaml new file mode 120000 index 000000000..9dc1ea992 --- /dev/null +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous-nautilus/luminous-client-x/rbd/supported/ubuntu_16.04.yaml @@ -0,0 +1 @@ +../../../../../../distros/all/ubuntu_16.04.yaml \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous/luminous-client-x/basic/1-install/luminous-client-x.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous/luminous-client-x/basic/1-install/luminous-client-x.yaml index 3e190f0d5..56137a9a5 100644 --- a/ceph/qa/suites/upgrade/client-upgrade-luminous/luminous-client-x/basic/1-install/luminous-client-x.yaml +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous/luminous-client-x/basic/1-install/luminous-client-x.yaml @@ -1,7 +1,7 @@ tasks: - install: branch: luminous - exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev'] + exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev','python34-cephfs','python34-rados'] - print: "**** done install luminous" upgrade_workload: sequential: diff --git a/ceph/qa/suites/upgrade/client-upgrade-luminous/luminous-client-x/rbd/1-install/luminous-client-x.yaml b/ceph/qa/suites/upgrade/client-upgrade-luminous/luminous-client-x/rbd/1-install/luminous-client-x.yaml index 4a4553546..463bb5c6e 100644 --- a/ceph/qa/suites/upgrade/client-upgrade-luminous/luminous-client-x/rbd/1-install/luminous-client-x.yaml +++ b/ceph/qa/suites/upgrade/client-upgrade-luminous/luminous-client-x/rbd/1-install/luminous-client-x.yaml @@ -1,7 +1,7 @@ tasks: - install: branch: luminous - exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev'] + exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev','python34-cephfs','python34-rados'] - print: "**** done install luminous" - install.upgrade: exclude_packages: ['ceph-test', 'ceph-test-dbg','libcephfs1'] diff --git a/ceph/qa/suites/upgrade/jewel-x/parallel/1-jewel-install/jewel.yaml b/ceph/qa/suites/upgrade/jewel-x/parallel/1-jewel-install/jewel.yaml index 0471509b2..16d9c81b6 100644 --- a/ceph/qa/suites/upgrade/jewel-x/parallel/1-jewel-install/jewel.yaml +++ b/ceph/qa/suites/upgrade/jewel-x/parallel/1-jewel-install/jewel.yaml @@ -25,7 +25,7 @@ meta: tasks: - install: branch: jewel - exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev','python34-cephfs','python34-rados','python34-rbd','python34-rgw','python34-ceph-argparse','python3-cephfs','python3-rados'] + exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev','python36-cephfs','python36-rados','python36-rbd','python36-rgw','python36-ceph-argparse','python3-cephfs','python3-rados'] - print: "**** done installing jewel" - ceph: skip_mgr_daemons: true diff --git a/ceph/qa/suites/upgrade/jewel-x/parallel/7-final-workload/rgw_swift.yaml b/ceph/qa/suites/upgrade/jewel-x/parallel/7-final-workload/rgw_swift.yaml index 780c4ad70..d676486c2 100644 --- a/ceph/qa/suites/upgrade/jewel-x/parallel/7-final-workload/rgw_swift.yaml +++ b/ceph/qa/suites/upgrade/jewel-x/parallel/7-final-workload/rgw_swift.yaml @@ -9,5 +9,6 @@ tasks: - print: "**** done rgw 7-final-workload" - swift: client.1: + force-branch: ceph-luminous rgw_server: client.1 - print: "**** done swift 7-final-workload" diff --git a/ceph/qa/suites/upgrade/jewel-x/stress-split/1-jewel-install/jewel.yaml b/ceph/qa/suites/upgrade/jewel-x/stress-split/1-jewel-install/jewel.yaml index 87bebb445..b8f748ff1 100644 --- a/ceph/qa/suites/upgrade/jewel-x/stress-split/1-jewel-install/jewel.yaml +++ b/ceph/qa/suites/upgrade/jewel-x/stress-split/1-jewel-install/jewel.yaml @@ -3,7 +3,7 @@ meta: tasks: - install: branch: jewel - exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev','python34-cephfs','python34-rados','python34-rbd','python34-rgw','python34-ceph-argparse','python3-cephfs','python3-rados'] + exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev','python36-cephfs','python36-rados','python36-rbd','python36-rgw','python36-ceph-argparse','python3-cephfs','python3-rados'] - print: "**** done install jewel" - ceph: skip_mgr_daemons: true diff --git a/ceph/qa/suites/upgrade/jewel-x/stress-split/7-final-workload/rgw-swift.yaml b/ceph/qa/suites/upgrade/jewel-x/stress-split/7-final-workload/rgw-swift.yaml index 76e5d6fc2..aca66ba62 100644 --- a/ceph/qa/suites/upgrade/jewel-x/stress-split/7-final-workload/rgw-swift.yaml +++ b/ceph/qa/suites/upgrade/jewel-x/stress-split/7-final-workload/rgw-swift.yaml @@ -7,5 +7,6 @@ tasks: - print: "**** done rgw 9-workload" - swift: client.0: + force-branch: ceph-luminous rgw_server: client.0 - print: "**** done swift 9-workload" diff --git a/ceph/qa/suites/upgrade/kraken-x/parallel/7-final-workload/rgw_swift.yaml b/ceph/qa/suites/upgrade/kraken-x/parallel/7-final-workload/rgw_swift.yaml index 7a7659ff4..45e9f3a3a 100644 --- a/ceph/qa/suites/upgrade/kraken-x/parallel/7-final-workload/rgw_swift.yaml +++ b/ceph/qa/suites/upgrade/kraken-x/parallel/7-final-workload/rgw_swift.yaml @@ -9,5 +9,6 @@ tasks: - print: "**** done rgw 4-final-workload" - swift: client.1: + force-branch: ceph-luminous rgw_server: client.1 - print: "**** done swift 4-final-workload" diff --git a/ceph/qa/suites/upgrade/kraken-x/stress-split/7-final-workload/rgw-swift.yaml b/ceph/qa/suites/upgrade/kraken-x/stress-split/7-final-workload/rgw-swift.yaml index 76e5d6fc2..aca66ba62 100644 --- a/ceph/qa/suites/upgrade/kraken-x/stress-split/7-final-workload/rgw-swift.yaml +++ b/ceph/qa/suites/upgrade/kraken-x/stress-split/7-final-workload/rgw-swift.yaml @@ -7,5 +7,6 @@ tasks: - print: "**** done rgw 9-workload" - swift: client.0: + force-branch: ceph-luminous rgw_server: client.0 - print: "**** done swift 9-workload" diff --git a/ceph/qa/suites/upgrade/luminous-p2p/luminous-p2p-stress-split/7-final-workload/rgw-swift.yaml b/ceph/qa/suites/upgrade/luminous-p2p/luminous-p2p-stress-split/7-final-workload/rgw-swift.yaml index 76e5d6fc2..aca66ba62 100644 --- a/ceph/qa/suites/upgrade/luminous-p2p/luminous-p2p-stress-split/7-final-workload/rgw-swift.yaml +++ b/ceph/qa/suites/upgrade/luminous-p2p/luminous-p2p-stress-split/7-final-workload/rgw-swift.yaml @@ -7,5 +7,6 @@ tasks: - print: "**** done rgw 9-workload" - swift: client.0: + force-branch: ceph-luminous rgw_server: client.0 - print: "**** done swift 9-workload" diff --git a/ceph/qa/tasks/ceph.conf.template b/ceph/qa/tasks/ceph.conf.template new file mode 100644 index 000000000..93363cddd --- /dev/null +++ b/ceph/qa/tasks/ceph.conf.template @@ -0,0 +1,92 @@ +[global] + chdir = "" + pid file = /var/run/ceph/$cluster-$name.pid + auth supported = cephx + + filestore xattr use omap = true + + mon clock drift allowed = 1.000 + + osd crush chooseleaf type = 0 + auth debug = true + + ms die on old message = true + + mon pg warn min per osd = 1 + mon pg warn max per osd = 10000 # <= luminous + mon max pg per osd = 10000 # >= luminous + mon pg warn max object skew = 0 + + osd pool default size = 2 + + mon osd allow primary affinity = true + mon osd allow pg remap = true + mon warn on legacy crush tunables = false + mon warn on crush straw calc version zero = false + mon warn on no sortbitwise = false + mon warn on osd down out interval zero = false + mon warn on too few osds = false + + osd pool default erasure code profile = "plugin=jerasure technique=reed_sol_van k=2 m=1 ruleset-failure-domain=osd crush-failure-domain=osd" + + osd default data pool replay window = 5 + + mon allow pool delete = true + + mon cluster log file level = debug + debug asserts on shutdown = true + +[osd] + osd journal size = 100 + + osd scrub load threshold = 5.0 + osd scrub max interval = 600 + + osd recover clone overlap = true + osd recovery max chunk = 1048576 + + osd debug shutdown = true + osd debug op order = true + osd debug verify stray on activate = true + + osd open classes on start = true + osd debug pg log writeout = true + + osd deep scrub update digest min age = 30 + + osd map max advance = 10 + + journal zero on create = true + + filestore ondisk finisher threads = 3 + filestore apply finisher threads = 3 + + bdev debug aio = true + osd debug misdirected ops = true + +[mgr] + debug ms = 1 + debug mgr = 20 + debug mon = 20 + debug auth = 20 + mon reweight min pgs per osd = 4 + mon reweight min bytes per osd = 10 + +[mon] + debug ms = 1 + debug mon = 20 + debug paxos = 20 + debug auth = 20 + mon data avail warn = 5 + mon mgr mkfs grace = 120 + mon reweight min pgs per osd = 4 + mon osd reporter subtree level = osd + mon osd prime pg temp = true + mon reweight min bytes per osd = 10 + +[client] + rgw cache enabled = true + rgw enable ops log = true + rgw enable usage log = true + log file = /var/log/ceph/$cluster-$name.$pid.log + admin socket = /var/run/ceph/$cluster-$name.$pid.asok diff --git a/ceph/qa/tasks/ceph.py b/ceph/qa/tasks/ceph.py index f61047d98..ecee234f9 100644 --- a/ceph/qa/tasks/ceph.py +++ b/ceph/qa/tasks/ceph.py @@ -6,6 +6,7 @@ Handle the setup, starting, and clean-up of a Ceph cluster. from cStringIO import StringIO import argparse +import configobj import contextlib import errno import logging @@ -13,6 +14,7 @@ import os import json import time import gevent +import re import socket from paramiko import SSHException @@ -381,6 +383,110 @@ def cephfs_setup(ctx, config): yield +def get_mons(roles, ips, cluster_name): + """ + Get monitors and their associated addresses + """ + mons = {} + ports = {} + mon_id = 0 + is_mon = teuthology.is_type('mon', cluster_name) + for idx, roles in enumerate(roles): + for role in roles: + if not is_mon(role): + continue + if ips[idx] not in ports: + ports[ips[idx]] = 6789 + else: + ports[ips[idx]] += 1 + addr = '{ip}:{port}'.format( + ip=ips[idx], + port=ports[ips[idx]], + ) + mon_id += 1 + mons[role] = addr + assert mons + return mons + +def skeleton_config(ctx, roles, ips, mons, cluster='ceph'): + """ + Returns a ConfigObj that is prefilled with a skeleton config. + + Use conf[section][key]=value or conf.merge to change it. + + Use conf.write to write it out, override .filename first if you want. + """ + path = os.path.join(os.path.dirname(__file__), 'ceph.conf.template') + t = open(path, 'r') + skconf = t.read().format(testdir=teuthology.get_testdir(ctx)) + conf = configobj.ConfigObj(StringIO(skconf), file_error=True) + mon_hosts = [] + for role, addr in mons.iteritems(): + mon_cluster, _, _ = teuthology.split_role(role) + if mon_cluster != cluster: + continue + name = teuthology.ceph_role(role) + conf.setdefault(name, {}) + mon_hosts.append(addr) + conf.setdefault('global', {}) + conf['global']['mon host'] = ','.join(mon_hosts) + # set up standby mds's + is_mds = teuthology.is_type('mds', cluster) + for roles_subset in roles: + for role in roles_subset: + if is_mds(role): + name = teuthology.ceph_role(role) + conf.setdefault(name, {}) + if '-s-' in name: + standby_mds = name[name.find('-s-') + 3:] + conf[name]['mds standby for name'] = standby_mds + return conf + +def create_simple_monmap(ctx, remote, conf, mons, + path=None): + """ + Writes a simple monmap based on current ceph.conf into path, or + /monmap by default. + + Assumes ceph_conf is up to date. + + Assumes mon sections are named "mon.*", with the dot. + + :return the FSID (as a string) of the newly created monmap + """ + + addresses = list(mons.iteritems()) + assert addresses, "There are no monitors in config!" + log.debug('Ceph mon addresses: %s', addresses) + + testdir = teuthology.get_testdir(ctx) + args = [ + 'adjust-ulimits', + 'ceph-coverage', + '{tdir}/archive/coverage'.format(tdir=testdir), + 'monmaptool', + '--create', + '--clobber', + ] + for (role, addr) in addresses: + _, _, n = teuthology.split_role(role) + args.extend(('--add', n, addr)) + if not path: + path = '{tdir}/monmap'.format(tdir=testdir) + args.extend([ + '--print', + path + ]) + + r = remote.run( + args=args, + stdout=StringIO() + ) + monmap_output = r.stdout.getvalue() + fsid = re.search("generated fsid (.+)$", + monmap_output, re.MULTILINE).group(1) + return fsid + @contextlib.contextmanager def cluster(ctx, config): """ @@ -480,7 +586,10 @@ def cluster(ctx, config): roles = [role_list for (remote, role_list) in remotes_and_roles] ips = [host for (host, port) in (remote.ssh.get_transport().getpeername() for (remote, role_list) in remotes_and_roles)] - conf = teuthology.skeleton_config(ctx, roles=roles, ips=ips, cluster=cluster_name) + mons = get_mons(roles, ips, cluster_name) + conf = skeleton_config( + ctx, roles=roles, ips=ips, mons=mons, cluster=cluster_name, + ) for remote, roles_to_journals in remote_to_roles_to_journals.iteritems(): for role, journal in roles_to_journals.iteritems(): name = teuthology.ceph_role(role) @@ -501,6 +610,7 @@ def cluster(ctx, config): ctx.ceph = {} ctx.ceph[cluster_name] = argparse.Namespace() ctx.ceph[cluster_name].conf = conf + ctx.ceph[cluster_name].mons = mons default_keyring = '/etc/ceph/{cluster}.keyring'.format(cluster=cluster_name) keyring_path = config.get('keyring_path', default_keyring) @@ -544,10 +654,11 @@ def cluster(ctx, config): (mon0_remote,) = ctx.cluster.only(firstmon).remotes.keys() monmap_path = '{tdir}/{cluster}.monmap'.format(tdir=testdir, cluster=cluster_name) - fsid = teuthology.create_simple_monmap( + fsid = create_simple_monmap( ctx, remote=mon0_remote, conf=conf, + mons=mons, path=monmap_path, ) if not 'global' in conf: diff --git a/ceph/qa/tasks/ceph_deploy.py b/ceph/qa/tasks/ceph_deploy.py index 3d4c7c8d3..ed404447d 100644 --- a/ceph/qa/tasks/ceph_deploy.py +++ b/ceph/qa/tasks/ceph_deploy.py @@ -46,7 +46,7 @@ def download_ceph_deploy(ctx, config): system_type = teuthology.get_system_type(ceph_admin) if system_type == 'rpm': - package = 'python34' if py_ver == '3' else 'python' + package = 'python36' if py_ver == '3' else 'python' ctx.cluster.run(args=[ 'sudo', 'yum', '-y', 'install', package, 'python-virtualenv' diff --git a/ceph/qa/tasks/ceph_manager.py b/ceph/qa/tasks/ceph_manager.py index 969cd6e23..30e48950c 100644 --- a/ceph/qa/tasks/ceph_manager.py +++ b/ceph/qa/tasks/ceph_manager.py @@ -2505,7 +2505,7 @@ class CephManager: """ Extract all the monitor status information from the cluster """ - addr = self.ctx.ceph[self.cluster].conf['mon.%s' % mon]['mon addr'] + addr = self.ctx.ceph[self.cluster].mons['mon.%s' % mon] out = self.raw_cluster_cmd('-m', addr, 'mon_status') return json.loads(out) diff --git a/ceph/qa/tasks/cephfs/test_client_limits.py b/ceph/qa/tasks/cephfs/test_client_limits.py index bc029cd8a..706f4af0a 100644 --- a/ceph/qa/tasks/cephfs/test_client_limits.py +++ b/ceph/qa/tasks/cephfs/test_client_limits.py @@ -86,9 +86,7 @@ class TestClientLimits(CephFSTestCase): # which depend on the caps outstanding, cache size and overall ratio def expected_caps(): num_caps = self.get_session(mount_a_client_id)['num_caps'] - if num_caps < mds_min_caps_per_client: - raise RuntimeError("client caps fell below min!") - elif num_caps == mds_min_caps_per_client: + if num_caps <= mds_min_caps_per_client: return True elif num_caps < cache_size: return True @@ -253,9 +251,7 @@ class TestClientLimits(CephFSTestCase): mount_a_client_id = self.mount_a.get_global_id() def expected_caps(): num_caps = self.get_session(mount_a_client_id)['num_caps'] - if num_caps < mds_min_caps_per_client: - raise RuntimeError("client caps fell below min!") - elif num_caps <= mds_max_caps_per_client: + if num_caps <= mds_max_caps_per_client: return True else: return False diff --git a/ceph/qa/tasks/cephfs/test_client_recovery.py b/ceph/qa/tasks/cephfs/test_client_recovery.py index 2b91cbfe6..880208a4d 100644 --- a/ceph/qa/tasks/cephfs/test_client_recovery.py +++ b/ceph/qa/tasks/cephfs/test_client_recovery.py @@ -519,3 +519,21 @@ class TestClientRecovery(CephFSTestCase): self.fs.mds_asok(['session', 'evict', "%s" % mount_a_client_id]) self.mount_a.umount_wait(require_clean=True, timeout=30) + + def test_config_session_timeout(self): + session_timeout = self.fs.get_var("session_timeout") + mount_a_gid = self.mount_a.get_global_id() + + self.fs.mds_asok(['session', 'config', '%s' % mount_a_gid, 'timeout', '%s' % (session_timeout * 2)]) + + self.mount_a.kill(); + + self.assert_session_count(2) + + time.sleep(session_timeout * 1.5) + self.assert_session_state(mount_a_gid, "open") + + time.sleep(session_timeout) + self.assert_session_count(1) + + self.mount_a.kill_cleanup() diff --git a/ceph/qa/tasks/cephfs/test_misc.py b/ceph/qa/tasks/cephfs/test_misc.py index 9c44e6c09..6507e374b 100644 --- a/ceph/qa/tasks/cephfs/test_misc.py +++ b/ceph/qa/tasks/cephfs/test_misc.py @@ -123,6 +123,7 @@ class TestMisc(CephFSTestCase): ls_data = self.fs.mds_asok(['session', 'ls']) self.assert_session_count(1, ls_data) + mount_a_client_id = self.mount_a.get_global_id() self.mount_a.kill() self.mount_a.kill_cleanup() @@ -130,6 +131,8 @@ class TestMisc(CephFSTestCase): ls_data = self.fs.mds_asok(['session', 'ls']) self.assert_session_count(1, ls_data) + self.fs.mds_asok(['session', 'evict', "%s" % mount_a_client_id]) + self.mount_a.mount() self.mount_a.wait_until_mounted() self.mount_b.mount() @@ -216,74 +219,126 @@ class TestMisc(CephFSTestCase): ratio = raw_avail / fs_avail assert 0.9 < ratio < 1.1 - def _run_drop_cache_cmd(self, timeout, use_tell): - drop_res = None +class TestCacheDrop(CephFSTestCase): + CLIENTS_REQUIRED = 1 + + def _run_drop_cache_cmd(self, use_tell, timeout=None): + result = None + mds_id = self.fs.get_lone_mds_id() if use_tell: - mds_id = self.fs.get_lone_mds_id() - drop_res = json.loads( - self.fs.mon_manager.raw_cluster_cmd("tell", "mds.{0}".format(mds_id), - "cache", "drop", str(timeout))) + if timeout is not None: + result = json.loads(self.fs.mon_manager.raw_cluster_cmd("tell", "mds.{0}".format(mds_id), + "cache", "drop", str(timeout))) + else: + result = json.loads(self.fs.mon_manager.raw_cluster_cmd("tell", "mds.{0}".format(mds_id), + "cache", "drop")) else: - drop_res = self.fs.mds_asok(["cache", "drop", str(timeout)]) - return drop_res - - def _drop_cache_command(self, timeout, use_tell=True): - self.mount_b.umount_wait() - ls_data = self.fs.mds_asok(['session', 'ls']) - self.assert_session_count(1, ls_data) + if timeout is None: + result = self.fs.mds_asok(["cache", "drop"]) + else: + result = self.fs.mds_asok(["cache", "drop", str(timeout)]) + return result + def _setup(self, max_caps=20, threshold=400): # create some files - self.mount_a.create_n_files("dc-dir/dc-file", 1000) - # drop cache - drop_res = self._run_drop_cache_cmd(timeout, use_tell) + self.mount_a.create_n_files("dc-dir/dc-file", 1000, sync=True) - self.assertTrue(drop_res['client_recall']['return_code'] == 0) - self.assertTrue(drop_res['flush_journal']['return_code'] == 0) - - def _drop_cache_command_timeout(self, timeout, use_tell=True): - self.mount_b.umount_wait() - ls_data = self.fs.mds_asok(['session', 'ls']) - self.assert_session_count(1, ls_data) - - # create some files - self.mount_a.create_n_files("dc-dir/dc-file-t", 1000) - - # simulate client death and try drop cache - self.mount_a.kill() - drop_res = self._run_drop_cache_cmd(timeout, use_tell) - - self.assertTrue(drop_res['client_recall']['return_code'] == -errno.ETIMEDOUT) - self.assertTrue(drop_res['flush_journal']['return_code'] == 0) - - self.mount_a.kill_cleanup() - self.mount_a.mount() - self.mount_a.wait_until_mounted() + # Reduce this so the MDS doesn't rkcall the maximum for simple tests + self.fs.rank_asok(['config', 'set', 'mds_recall_max_caps', str(max_caps)]) + self.fs.rank_asok(['config', 'set', 'mds_recall_max_decay_threshold', str(threshold)]) def test_drop_cache_command_asok(self): """ - Basic test for checking drop cache command using admin socket. + Basic test for checking drop cache command. + Confirm it halts without a timeout. Note that the cache size post trimming is not checked here. """ - self._drop_cache_command(10, use_tell=False) + mds_min_caps_per_client = int(self.fs.get_config("mds_min_caps_per_client")) + self._setup() + result = self._run_drop_cache_cmd(False) + self.assertTrue(result['client_recall']['return_code'] == 0) + self.assertTrue(result['flush_journal']['return_code'] == 0) + # It should take at least 1 second + self.assertTrue(result['duration'] > 1) + self.assertGreaterEqual(result['trim_cache']['trimmed'], 1000-2*mds_min_caps_per_client) def test_drop_cache_command_tell(self): """ - Basic test for checking drop cache command using tell interface. + Basic test for checking drop cache command. + Confirm it halts without a timeout. Note that the cache size post trimming is not checked here. """ - self._drop_cache_command(10) + mds_min_caps_per_client = int(self.fs.get_config("mds_min_caps_per_client")) + self._setup() + result = self._run_drop_cache_cmd(True) + self.assertTrue(result['client_recall']['return_code'] == 0) + self.assertTrue(result['flush_journal']['return_code'] == 0) + # It should take at least 1 second + self.assertTrue(result['duration'] > 1) + self.assertGreaterEqual(result['trim_cache']['trimmed'], 1000-2*mds_min_caps_per_client) def test_drop_cache_command_timeout_asok(self): """ - Check drop cache command with non-responding client using admin - socket. Note that the cache size post trimming is not checked here. + Basic test for checking drop cache command. + Confirm recall halts early via a timeout. + Note that the cache size post trimming is not checked here. """ - self._drop_cache_command_timeout(5, use_tell=False) + self._setup() + # simulate client death and try drop cache + self.mount_a.kill() + result = self._run_drop_cache_cmd(False, timeout=10) + self.assertTrue(result['client_recall']['return_code'] == -errno.ETIMEDOUT) + self.assertTrue(result['flush_journal']['return_code'] == 0) + self.assertTrue(result['duration'] > 10) def test_drop_cache_command_timeout_tell(self): + """ + Basic test for checking drop cache command. + Confirm recall halts early via a timeout. + Note that the cache size post trimming is not checked here. + """ + self._setup() + # simulate client death and try drop cache + self.mount_a.kill() + result = self._run_drop_cache_cmd(True, timeout=10) + self.assertTrue(result['client_recall']['return_code'] == -errno.ETIMEDOUT) + self.assertTrue(result['flush_journal']['return_code'] == 0) + self.assertTrue(result['duration'] > 10) + + def test_drop_cache_command_dead_timeout(self): """ Check drop cache command with non-responding client using tell interface. Note that the cache size post trimming is not checked here. """ - self._drop_cache_command_timeout(5) + self._setup() + self.mount_a.kill() + # Note: recall is subject to the timeout. The journal flush will + # be delayed due to the client being dead. + result = self._run_drop_cache_cmd(True, timeout=5) + self.assertTrue(result['client_recall']['return_code'] == -errno.ETIMEDOUT) + self.assertTrue(result['flush_journal']['return_code'] == 0) + self.assertTrue(result['duration'] > 5) + self.assertTrue(result['duration'] < 120) + self.assertEqual(0, result['trim_cache']['trimmed']) + self.mount_a.kill_cleanup() + self.mount_a.mount() + self.mount_a.wait_until_mounted() + + def test_drop_cache_command_dead(self): + """ + Check drop cache command with non-responding client using tell + interface. Note that the cache size post trimming is not checked + here. + """ + self._setup() + self.mount_a.kill() + result = self._run_drop_cache_cmd(True) + self.assertTrue(result['client_recall']['return_code'] == 0) + self.assertTrue(result['flush_journal']['return_code'] == 0) + self.assertTrue(result['duration'] > 5) + self.assertTrue(result['duration'] < 120) + self.assertEqual(0, result['trim_cache']['trimmed']) + self.mount_a.kill_cleanup() + self.mount_a.mount() + self.mount_a.wait_until_mounted() diff --git a/ceph/qa/tasks/mgr/test_module_selftest.py b/ceph/qa/tasks/mgr/test_module_selftest.py index b7fb57061..673136c79 100644 --- a/ceph/qa/tasks/mgr/test_module_selftest.py +++ b/ceph/qa/tasks/mgr/test_module_selftest.py @@ -41,6 +41,9 @@ class TestModuleSelftest(MgrTestCase): self._load_module("selftest") self.mgr_cluster.mon_manager.raw_cluster_cmd("mgr", "self-test", "run") + def test_telemetry(self): + self._selftest_plugin("telemetry") + def test_selftest_command_spam(self): # Use the selftest module to stress the mgr daemon self._load_module("selftest") diff --git a/ceph/qa/tasks/mon_seesaw.py b/ceph/qa/tasks/mon_seesaw.py index b101c0e41..1a70c1d47 100644 --- a/ceph/qa/tasks/mon_seesaw.py +++ b/ceph/qa/tasks/mon_seesaw.py @@ -23,7 +23,7 @@ def _get_next_port(ctx, ip, cluster): # assuming we have only one cluster here. used = [] for name in teuthology.get_mon_names(ctx, cluster): - addr = ctx.ceph[cluster].conf[name]['mon addr'] + addr = ctx.ceph[cluster].mons[name] mon_ip, mon_port = addr.split(':') if mon_ip != ip: continue diff --git a/ceph/qa/tasks/radosgw_admin.py b/ceph/qa/tasks/radosgw_admin.py index f23a3b9ef..57857949f 100644 --- a/ceph/qa/tasks/radosgw_admin.py +++ b/ceph/qa/tasks/radosgw_admin.py @@ -16,7 +16,6 @@ import logging import time import datetime import Queue -import bunch import sys @@ -207,7 +206,7 @@ class requestlog_queue(): pass elif response.status < 200 or response.status >= 400: error = True - self.q.put(bunch.Bunch({'t': now, 'o': request, 'i': response, 'e': error})) + self.q.put({'t': now, 'o': request, 'i': response, 'e': error}) def clear(self): with self.q.mutex: self.q.queue.clear() @@ -215,16 +214,16 @@ class requestlog_queue(): while not self.q.empty(): j = self.q.get() bytes_out = 0 - if 'Content-Length' in j.o.headers: - bytes_out = int(j.o.headers['Content-Length']) + if 'Content-Length' in j['o'].headers: + bytes_out = int(j['o'].headers['Content-Length']) bytes_in = 0 - if 'content-length' in j.i.msg.dict: - bytes_in = int(j.i.msg.dict['content-length']) + if 'content-length' in j['i'].msg.dict: + bytes_in = int(j['i'].msg.dict['content-length']) log.info('RL: %s %s %s bytes_out=%d bytes_in=%d failed=%r' - % (cat, bucket, user, bytes_out, bytes_in, j.e)) + % (cat, bucket, user, bytes_out, bytes_in, j['e'])) if add_entry == None: add_entry = self.adder - add_entry(cat, bucket, user, bytes_out, bytes_in, j.e) + add_entry(cat, bucket, user, bytes_out, bytes_in, j['e']) def create_presigned_url(conn, method, bucket_name, key_name, expiration): return conn.generate_url(expires_in=expiration, diff --git a/ceph/qa/tasks/radosgw_admin_rest.py b/ceph/qa/tasks/radosgw_admin_rest.py index 99a742f13..fd78cf140 100644 --- a/ceph/qa/tasks/radosgw_admin_rest.py +++ b/ceph/qa/tasks/radosgw_admin_rest.py @@ -235,6 +235,33 @@ def task(ctx, config): assert ret == 200 + # TESTCASE 'list-no-user','user','list','list user keys','user list object' + (ret, out) = rgwadmin_rest(admin_conn, ['user', 'list'], {'max-entries' : 0}) + assert ret == 200 + assert out['count'] == 0 + assert out['truncated'] == True + assert len(out['keys']) == 0 + assert len(out['marker']) > 0 + + # TESTCASE 'list-user-without-marker','user','list','list user keys','user list object' + (ret, out) = rgwadmin_rest(admin_conn, ['user', 'list'], {'max-entries' : 1}) + assert ret == 200 + assert out['count'] == 1 + assert out['truncated'] == True + assert len(out['keys']) == 1 + assert len(out['marker']) > 0 + marker = out['marker'] + + # TESTCASE 'list-user-with-marker','user','list','list user keys','user list object' + (ret, out) = rgwadmin_rest(admin_conn, ['user', 'list'], {'max-entries' : 1, 'marker': marker}) + assert ret == 200 + assert out['count'] == 1 + assert out['truncated'] == False + assert len(out['keys']) == 1 + + (ret, out) = rgwadmin_rest(admin_conn, ['user', 'list'], {'max-entries' : 1, + 'marker': }) + # TESTCASE 'info-existing','user','info','existing user','returns correct info' (ret, out) = rgwadmin_rest(admin_conn, ['user', 'info'], {'uid' : user1}) diff --git a/ceph/qa/tasks/rbd_fio.py b/ceph/qa/tasks/rbd_fio.py index 663e8f524..a993c20a7 100644 --- a/ceph/qa/tasks/rbd_fio.py +++ b/ceph/qa/tasks/rbd_fio.py @@ -206,8 +206,8 @@ def run_fio(remote, config, rbd_test_dir): fio = "https://github.com/axboe/fio/archive/fio-" + fio_version + ".tar.gz" remote.run(args=['mkdir', run.Raw(rbd_test_dir),]) remote.run(args=['cd' , run.Raw(rbd_test_dir), - run.Raw(';'), 'wget' , fio , run.Raw(';'), run.Raw('tar -xvf fio*tar.gz'), run.Raw(';'), - run.Raw('cd fio-fio*'), 'configure', run.Raw(';') ,'make']) + run.Raw(';'), 'wget', fio, run.Raw(';'), run.Raw('tar -xvf fio*tar.gz'), run.Raw(';'), + run.Raw('cd fio-fio*'), run.Raw(';'), './configure', run.Raw(';'), 'make']) remote.run(args=['ceph', '-s']) remote.run(args=[run.Raw('{tdir}/fio-fio-{v}/fio --showcmd {f}'.format(tdir=rbd_test_dir,v=fio_version,f=fio_config.name))]) remote.run(args=['sudo', run.Raw('{tdir}/fio-fio-{v}/fio {f}'.format(tdir=rbd_test_dir,v=fio_version,f=fio_config.name))]) diff --git a/ceph/qa/tasks/rgw.py b/ceph/qa/tasks/rgw.py index cec0b648b..e75f07124 100644 --- a/ceph/qa/tasks/rgw.py +++ b/ceph/qa/tasks/rgw.py @@ -96,7 +96,8 @@ def start_rgw(ctx, config, clients): host, port = ctx.rgw.role_endpoints[client] endpoint = 'http://{host}:{port}/'.format(host=host, port=port) log.info('Polling {client} until it starts accepting connections on {endpoint}'.format(client=client, endpoint=endpoint)) - wait_for_radosgw(endpoint) + (remote,) = ctx.cluster.only(client).remotes.iterkeys() + wait_for_radosgw(endpoint, remote) try: yield diff --git a/ceph/qa/tasks/rgw_multisite.py b/ceph/qa/tasks/rgw_multisite.py index 668696b63..3026daf88 100644 --- a/ceph/qa/tasks/rgw_multisite.py +++ b/ceph/qa/tasks/rgw_multisite.py @@ -226,7 +226,7 @@ class Gateway(multisite.Gateway): """ (re)start the daemon """ self.daemon.restart() # wait until startup completes - wait_for_radosgw(self.endpoint()) + wait_for_radosgw(self.endpoint(), self.remote) def stop(self): """ stop the daemon """ diff --git a/ceph/qa/tasks/s3readwrite.py b/ceph/qa/tasks/s3readwrite.py index 9f1507ef8..01e78ecfd 100644 --- a/ceph/qa/tasks/s3readwrite.py +++ b/ceph/qa/tasks/s3readwrite.py @@ -18,29 +18,32 @@ from teuthology.orchestra.connection import split_user log = logging.getLogger(__name__) - @contextlib.contextmanager def download(ctx, config): """ Download the s3 tests from the git builder. Remove downloaded s3 file upon exit. - + The context passed in should be identical to the context passed in to the main task. """ assert isinstance(config, dict) log.info('Downloading s3-tests...') testdir = teuthology.get_testdir(ctx) - for (client, cconf) in config.items(): - branch = cconf.get('force-branch', None) - if not branch: - branch = cconf.get('branch', 'master') - sha1 = cconf.get('sha1') + for (client, client_config) in config.items(): + s3tests_branch = client_config.get('force-branch', None) + if not s3tests_branch: + raise ValueError( + "Could not determine what branch to use for s3-tests. Please add 'force-branch: {s3-tests branch name}' to the .yaml config for this s3readwrite task.") + + log.info("Using branch '%s' for s3tests", s3tests_branch) + sha1 = client_config.get('sha1') + git_remote = client_config.get('git_remote', teuth_config.ceph_git_base_url) ctx.cluster.only(client).run( args=[ 'git', 'clone', - '-b', branch, - teuth_config.ceph_git_base_url + 's3-tests.git', + '-b', s3tests_branch, + git_remote + 's3-tests.git', '{tdir}/s3-tests'.format(tdir=testdir), ], ) diff --git a/ceph/qa/tasks/s3roundtrip.py b/ceph/qa/tasks/s3roundtrip.py index 620b9d42d..74a61223d 100644 --- a/ceph/qa/tasks/s3roundtrip.py +++ b/ceph/qa/tasks/s3roundtrip.py @@ -18,35 +18,48 @@ from teuthology.orchestra.connection import split_user log = logging.getLogger(__name__) - @contextlib.contextmanager def download(ctx, config): """ Download the s3 tests from the git builder. Remove downloaded s3 file upon exit. - + The context passed in should be identical to the context passed in to the main task. """ assert isinstance(config, dict) log.info('Downloading s3-tests...') testdir = teuthology.get_testdir(ctx) - for (client, cconf) in config.iteritems(): - branch = cconf.get('force-branch', None) - if not branch: - branch = cconf.get('branch', 'master') + for (client, client_config) in config.items(): + s3tests_branch = client_config.get('force-branch', None) + if not s3tests_branch: + raise ValueError( + "Could not determine what branch to use for s3-tests. Please add 'force-branch: {s3-tests branch name}' to the .yaml config for this s3roundtrip task.") + + log.info("Using branch '%s' for s3tests", s3tests_branch) + sha1 = client_config.get('sha1') + git_remote = client_config.get('git_remote', teuth_config.ceph_git_base_url) ctx.cluster.only(client).run( args=[ 'git', 'clone', - '-b', branch, - teuth_config.ceph_git_base_url + 's3-tests.git', + '-b', s3tests_branch, + git_remote + 's3-tests.git', '{tdir}/s3-tests'.format(tdir=testdir), ], ) + if sha1 is not None: + ctx.cluster.only(client).run( + args=[ + 'cd', '{tdir}/s3-tests'.format(tdir=testdir), + run.Raw('&&'), + 'git', 'reset', '--hard', sha1, + ], + ) try: yield finally: log.info('Removing s3-tests...') + testdir = teuthology.get_testdir(ctx) for client in config: ctx.cluster.only(client).run( args=[ @@ -56,6 +69,7 @@ def download(ctx, config): ], ) + def _config_user(s3tests_conf, section, user): """ Configure users for this section by stashing away keys, ids, and diff --git a/ceph/qa/tasks/s3tests.py b/ceph/qa/tasks/s3tests.py index 954983b8e..6bc715c09 100644 --- a/ceph/qa/tasks/s3tests.py +++ b/ceph/qa/tasks/s3tests.py @@ -30,27 +30,19 @@ def download(ctx, config): assert isinstance(config, dict) log.info('Downloading s3-tests...') testdir = teuthology.get_testdir(ctx) - s3_branches = [ 'giant', 'firefly', 'firefly-original', 'hammer' ] - for (client, cconf) in config.items(): - branch = cconf.get('force-branch', None) - if not branch: - ceph_branch = ctx.config.get('branch') - suite_branch = ctx.config.get('suite_branch', ceph_branch) - if suite_branch in s3_branches: - branch = cconf.get('branch', suite_branch) - else: - branch = cconf.get('branch', 'ceph-' + suite_branch) - if not branch: + for (client, client_config) in config.items(): + s3tests_branch = client_config.get('force-branch', None) + if not s3tests_branch: raise ValueError( - "Could not determine what branch to use for s3tests!") - else: - log.info("Using branch '%s' for s3tests", branch) - sha1 = cconf.get('sha1') - git_remote = cconf.get('git_remote', None) or teuth_config.ceph_git_base_url + "Could not determine what branch to use for s3-tests. Please add 'force-branch: {s3-tests branch name}' to the .yaml config for this s3tests task.") + + log.info("Using branch '%s' for s3tests", s3tests_branch) + sha1 = client_config.get('sha1') + git_remote = client_config.get('git_remote', teuth_config.ceph_git_base_url) ctx.cluster.only(client).run( args=[ 'git', 'clone', - '-b', branch, + '-b', s3tests_branch, git_remote + 's3-tests.git', '{tdir}/s3-tests'.format(tdir=testdir), ], @@ -228,10 +220,8 @@ def run_tests(ctx, config): """ assert isinstance(config, dict) testdir = teuthology.get_testdir(ctx) - attrs = ["!fails_on_rgw", "!lifecycle"] - # beast parser is strict about unreadable headers - if ctx.rgw.frontend == 'beast': - attrs.append("!fails_strict_rfc2616") + # civetweb > 1.8 && beast parsers are strict on rfc2616 + attrs = ["!fails_on_rgw", "!lifecycle_expiration", "!fails_strict_rfc2616"] for client, client_config in config.iteritems(): args = [ 'S3TEST_CONF={tdir}/archive/s3-tests.{client}.conf'.format(tdir=testdir, client=client), @@ -312,7 +302,9 @@ def task(ctx, config): tasks: - ceph: - rgw: [client.0] - - s3tests: [client.0] + - s3tests: + client.0: + force-branch: ceph-luminous To run against a server on client.1 and increase the boto timeout to 10m:: @@ -321,6 +313,7 @@ def task(ctx, config): - rgw: [client.1] - s3tests: client.0: + force-branch: ceph-luminous rgw_server: client.1 idle_timeout: 600 @@ -331,8 +324,10 @@ def task(ctx, config): - rgw: [client.0] - s3tests: client.0: + force-branch: ceph-luminous extra_args: ['test_s3:test_object_acl_grand_public_read'] client.1: + force-branch: ceph-luminous extra_args: ['--exclude', 'test_100_continue'] """ assert config is None or isinstance(config, list) \ @@ -364,6 +359,7 @@ def task(ctx, config): { 'port' : 7280, 'is_secure' : 'no', + 'api_name' : 'default', }, 'fixtures' : {}, 's3 main' : {}, diff --git a/ceph/qa/tasks/util/rgw.py b/ceph/qa/tasks/util/rgw.py index ab76b50a2..ee79208cc 100644 --- a/ceph/qa/tasks/util/rgw.py +++ b/ceph/qa/tasks/util/rgw.py @@ -2,6 +2,7 @@ from cStringIO import StringIO import logging import json import requests +import time from requests.packages.urllib3 import PoolManager from requests.packages.urllib3.util import Retry @@ -70,12 +71,29 @@ def get_user_successful_ops(out, user): return 0 return get_user_summary(out, user)['total']['successful_ops'] -def wait_for_radosgw(url): +def wait_for_radosgw(url, remote): """ poll the given url until it starts accepting connections add_daemon() doesn't wait until radosgw finishes startup, so this is used to avoid racing with later tasks that expect radosgw to be up and listening """ - # use a connection pool with retry/backoff to poll until it starts listening - http = PoolManager(retries=Retry(connect=8, backoff_factor=1)) - http.request('GET', url) + # TODO: use '--retry-connrefused --retry 8' when teuthology is running on + # Centos 8 and other OS's with an updated version of curl + curl_cmd = ['curl', + url] + exit_status = 0 + num_retries = 8 + for seconds in range(num_retries): + proc = remote.run( + args=curl_cmd, + check_status=False, + stdout=StringIO(), + stderr=StringIO(), + stdin=StringIO(), + ) + exit_status = proc.exitstatus + if exit_status == 0: + break + time.sleep(2**seconds) + + assert exit_status == 0 diff --git a/ceph/qa/workunits/ceph-disk/ceph-disk.sh b/ceph/qa/workunits/ceph-disk/ceph-disk.sh index 7102efba1..49f45ae84 100755 --- a/ceph/qa/workunits/ceph-disk/ceph-disk.sh +++ b/ceph/qa/workunits/ceph-disk/ceph-disk.sh @@ -1,13 +1,23 @@ #!/bin/bash -if [ -f $(dirname $0)/../ceph-helpers-root.sh ]; then - source $(dirname $0)/../ceph-helpers-root.sh +BASEDIR=$(dirname $0) +if [ -f $BASEDIR/../ceph-helpers-root.sh ]; then + source $BASEDIR/../ceph-helpers-root.sh else - echo "$(dirname $0)/../ceph-helpers-root.sh does not exist." + echo "$BASEDIR/../ceph-helpers-root.sh does not exist." exit 1 fi -install python-pytest || true -install pytest || true +PATH=$BASEDIR:$BASEDIR/..:$PATH + +: ${PYTHON:=python} +$PYTHON --version + +type pip + +# pytest supports python 2.7 up until the pytest 4.6 release, the 5.x series +# supports Python 3 only +sudo -H pip install "pytest==4.6.6" +$PYTHON -m pytest --version # complete the cluster setup done by the teuthology ceph task sudo chown $(id -u) /etc/ceph/ceph.conf @@ -20,27 +30,18 @@ fi sudo ceph osd crush rm osd.0 || true sudo ceph osd crush rm osd.1 || true -sudo cp $(dirname $0)/60-ceph-by-partuuid.rules /lib/udev/rules.d +sudo cp $BASEDIR/60-ceph-by-partuuid.rules /lib/udev/rules.d sudo udevadm control --reload -perl -pi -e 's|pid file.*|pid file = /var/run/ceph/\$cluster-\$name.pid|' /etc/ceph/ceph.conf +sudo perl -pi -e 's|pid file.*|pid file = /var/run/ceph/\$cluster-\$name.pid|' /etc/ceph/ceph.conf -PATH=$(dirname $0):$(dirname $0)/..:$PATH - -: ${PYTHON:=python} -PY_VERSION=$($PYTHON --version 2>&1) - -if ! ${PYTHON} -m pytest --version > /dev/null 2>&1; then - echo "py.test not installed for ${PY_VERSION}" - exit 1 -fi - -sudo env PATH=$(dirname $0):$(dirname $0)/..:$PATH PYTHONWARNINGS=ignore ${PYTHON} -m pytest -s -v $(dirname $0)/ceph-disk-test.py +sudo env PATH=$PATH PYTHONWARNINGS=ignore ${PYTHON} -m pytest -s -v --rootdir=$BASEDIR $BASEDIR/ceph-disk-test.py result=$? +sudo rm -rf $BASEDIR/.pytest_cache sudo rm -f /lib/udev/rules.d/60-ceph-by-partuuid.rules # own whatever was created as a side effect of the py.test run # so that it can successfully be removed later on by a non privileged # process -sudo chown -R $(id -u) $(dirname $0) +sudo chown -R $(id -u) $BASEDIR exit $result diff --git a/ceph/qa/workunits/ceph-helpers-root.sh b/ceph/qa/workunits/ceph-helpers-root.sh index f65f591f4..bc7017d55 100755 --- a/ceph/qa/workunits/ceph-helpers-root.sh +++ b/ceph/qa/workunits/ceph-helpers-root.sh @@ -17,26 +17,30 @@ ####################################################################### +function distro_id() { + source /etc/os-release + echo $ID +} + function install() { for package in "$@" ; do install_one $package done - return 0 } function install_one() { - case $(lsb_release -si) in - Ubuntu|Debian|Devuan) - sudo apt-get install -y "$@" + case $(distro_id) in + ubuntu|debian|devuan) + sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y "$@" ;; - CentOS|Fedora|RedHatEnterpriseServer) + centos|fedora|rhel) sudo yum install -y "$@" ;; - *SUSE*) + opensuse*|suse|sles) sudo zypper --non-interactive install "$@" ;; *) - echo "$(lsb_release -si) is unknown, $@ will have to be installed manually." + echo "$(distro_id) is unknown, $@ will have to be installed manually." ;; esac } diff --git a/ceph/qa/workunits/cephtool/test.sh b/ceph/qa/workunits/cephtool/test.sh index b0ab5c051..3c8c89095 100755 --- a/ceph/qa/workunits/cephtool/test.sh +++ b/ceph/qa/workunits/cephtool/test.sh @@ -2208,6 +2208,16 @@ function test_mon_osd_erasure_code() # clean up ceph osd erasure-code-profile rm fooprofile ceph osd erasure-code-profile rm barprofile + + # try weird k and m values + expect_false ceph osd erasure-code-profile set badk k=1 m=1 + expect_false ceph osd erasure-code-profile set badk k=1 m=2 + expect_false ceph osd erasure-code-profile set badk k=0 m=2 + expect_false ceph osd erasure-code-profile set badk k=-1 m=2 + expect_false ceph osd erasure-code-profile set badm k=2 m=0 + expect_false ceph osd erasure-code-profile set badm k=2 m=-1 + ceph osd erasure-code-profile set good k=2 m=1 + ceph osd erasure-code-profile rm good } function test_mon_osd_misc() diff --git a/ceph/qa/workunits/kernel_untar_build.sh b/ceph/qa/workunits/kernel_untar_build.sh index 93fee1f5b..a392b42f6 100755 --- a/ceph/qa/workunits/kernel_untar_build.sh +++ b/ceph/qa/workunits/kernel_untar_build.sh @@ -2,11 +2,11 @@ set -e -wget -q http://download.ceph.com/qa/linux-4.0.5.tar.xz +wget -O linux.tar.gz http://download.ceph.com/qa/linux-4.17.tar.gz mkdir t cd t -tar Jxvf ../linux*.xz +tar xzf ../linux.tar.gz cd linux* make defconfig make -j`grep -c processor /proc/cpuinfo` diff --git a/ceph/qa/workunits/mon/crush_ops.sh b/ceph/qa/workunits/mon/crush_ops.sh index 2ae820230..4e1cbb6e7 100755 --- a/ceph/qa/workunits/mon/crush_ops.sh +++ b/ceph/qa/workunits/mon/crush_ops.sh @@ -213,4 +213,18 @@ ceph osd crush rm fooo ceph osd crush rm barr ceph osd crush weight-set rm-compat +# this sequence would crash at one point +ceph osd crush weight-set create-compat +ceph osd crush add-bucket r1 rack +ceph osd crush move r1 root=default +for f in `seq 1 32`; do + ceph osd crush add-bucket h$f host + ceph osd crush move h$f rack=r1 +done +for f in `seq 1 32`; do + ceph osd crush rm h$f +done +ceph osd crush rm r1 +ceph osd crush weight-set rm-compat + echo OK diff --git a/ceph/qa/workunits/rados/test_alloc_hint.sh b/ceph/qa/workunits/rados/test_alloc_hint.sh index 3e246949d..846e4b633 100755 --- a/ceph/qa/workunits/rados/test_alloc_hint.sh +++ b/ceph/qa/workunits/rados/test_alloc_hint.sh @@ -51,6 +51,7 @@ function setup_pgid() { } function expect_alloc_hint_eq() { + export CEPH_ARGS="--osd-objectstore=filestore" local expected_extsize="$1" for (( i = 0 ; i < "${NUM_OSDS}" ; i++ )); do diff --git a/ceph/qa/workunits/rados/test_envlibrados_for_rocksdb.sh b/ceph/qa/workunits/rados/test_envlibrados_for_rocksdb.sh index c3c802d57..2139e88f1 100755 --- a/ceph/qa/workunits/rados/test_envlibrados_for_rocksdb.sh +++ b/ceph/qa/workunits/rados/test_envlibrados_for_rocksdb.sh @@ -2,29 +2,8 @@ ############################################ # Helper functions ############################################ -function install() { - for package in "$@" ; do - install_one $package - done - return 0 -} +source $(dirname $0)/../ceph-helpers-root.sh -function install_one() { - case $(lsb_release -si) in - Ubuntu|Debian|Devuan) - sudo apt-get install -y --force-yes "$@" - ;; - CentOS|Fedora|RedHatEnterpriseServer) - sudo yum install -y "$@" - ;; - *SUSE*) - sudo zypper --non-interactive install "$@" - ;; - *) - echo "$(lsb_release -si) is unknown, $@ will have to be installed manually." - ;; - esac -} ############################################ # Install required tools ############################################ @@ -38,15 +17,18 @@ CURRENT_PATH=`pwd` ############################################ # install prerequisites # for rocksdb -case $(lsb_release -si) in - Ubuntu|Debian|Devuan) - install g++-4.7 libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev librados-dev +case $(distro_id) in + ubuntu|debian|devuan) + install g++ libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev librados-dev ;; - CentOS|Fedora|RedHatEnterpriseServer) + centos|fedora|rhel) install gcc-c++.x86_64 gflags-devel snappy-devel zlib zlib-devel bzip2 bzip2-devel librados2-devel.x86_64 ;; + opensuse*|suse|sles) + install gcc-c++ snappy-devel zlib-devel libbz2-devel + ;; *) - echo "$(lsb_release -si) is unknown, $@ will have to be installed manually." + echo "$(distro_id) is unknown, $@ will have to be installed manually." ;; esac diff --git a/ceph/qa/workunits/rados/test_librados_build.sh b/ceph/qa/workunits/rados/test_librados_build.sh index 3aaaec7eb..c5166ffc6 100755 --- a/ceph/qa/workunits/rados/test_librados_build.sh +++ b/ceph/qa/workunits/rados/test_librados_build.sh @@ -8,6 +8,8 @@ # libradosstriper headers, boost headers, etc. - are already installed. # +source $(dirname $0)/../ceph-helpers-root.sh + trap cleanup EXIT SOURCES="hello_radosstriper.cc @@ -56,6 +58,14 @@ function run_binaries () { } pushd $DESTDIR +case $(distro_id) in + centos|fedora|rhel|opensuse*|suse|sles) + install gcc-c++ make librados-devel;; + ubuntu|debian|devuan) + install g++ make librados-dev;; + *) + echo "$(distro_id) is unknown, $@ will have to be installed manually." +esac get_sources check_sources make all-system diff --git a/ceph/qa/workunits/rbd/kernel.sh b/ceph/qa/workunits/rbd/kernel.sh index 5fb6b9358..e7736c87a 100755 --- a/ceph/qa/workunits/rbd/kernel.sh +++ b/ceph/qa/workunits/rbd/kernel.sh @@ -9,6 +9,10 @@ fi TMP_FILES="/tmp/img1 /tmp/img1.small /tmp/img1.snap1 /tmp/img1.export /tmp/img1.trunc" +function expect_false() { + if "$@"; then return 1; else return 0; fi +} + function get_device_dir { local POOL=$1 local IMAGE=$2 @@ -82,8 +86,9 @@ cmp /tmp/img1 /tmp/img1.snap1 sudo dd if=/dev/rbd/rbd/testimg1 of=/tmp/img1.export cmp /tmp/img1 /tmp/img1.export -# remove snapshot and detect error from mapped snapshot +# zeros are returned if an image or a snapshot is removed +expect_false cmp -n 76800000 /dev/rbd/rbd/testimg1@snap1 /dev/zero rbd snap rm --snap=snap1 testimg1 -sudo dd if=/dev/rbd/rbd/testimg1@snap1 of=/tmp/img1.snap1 2>&1 | grep 'Input/output error' +cmp -n 76800000 /dev/rbd/rbd/testimg1@snap1 /dev/zero echo OK diff --git a/ceph/qa/workunits/rbd/krbd_data_pool.sh b/ceph/qa/workunits/rbd/krbd_data_pool.sh index 7d7288213..4977e7d0e 100755 --- a/ceph/qa/workunits/rbd/krbd_data_pool.sh +++ b/ceph/qa/workunits/rbd/krbd_data_pool.sh @@ -61,7 +61,8 @@ function mkfs_and_mount() { local dev dev=$(sudo rbd map $spec) - mkfs.ext4 -q -E discard $dev + blkdiscard $dev + mkfs.ext4 -q -E nodiscard $dev sudo mount $dev /mnt sudo umount /mnt sudo rbd unmap $dev @@ -187,7 +188,7 @@ for pool in rbd rbdnonzero; do done done -# mkfs should discard some objects everywhere but in clonesonly +# mkfs_and_mount should discard some objects everywhere but in clonesonly [[ $(list_HEADs rbd | wc -l) -lt $((NUM_META_RBDS + 5 * NUM_OBJECTS)) ]] [[ $(list_HEADs repdata | wc -l) -lt $((1 + 14 * NUM_OBJECTS)) ]] [[ $(list_HEADs ecdata | wc -l) -lt $((1 + 14 * NUM_OBJECTS)) ]] diff --git a/ceph/qa/workunits/rbd/krbd_fallocate.sh b/ceph/qa/workunits/rbd/krbd_fallocate.sh index 05fc8a98c..712644ce0 100755 --- a/ceph/qa/workunits/rbd/krbd_fallocate.sh +++ b/ceph/qa/workunits/rbd/krbd_fallocate.sh @@ -1,12 +1,9 @@ #!/bin/bash -# This documents the state of things as of 4.12-rc4. -# # - fallocate -z deallocates because BLKDEV_ZERO_NOUNMAP hint is ignored by # krbd # -# - unaligned fallocate -z/-p appear to not deallocate -- see caveat #2 in -# linux.git commit 6ac56951dc10 ("rbd: implement REQ_OP_WRITE_ZEROES") +# - big unaligned blkdiscard and fallocate -z/-p leave the objects in place set -ex @@ -71,7 +68,7 @@ $(printf %x $IMAGE_SIZE) EOF [[ $(rados -p rbd ls | grep -c rbd_data.$IMAGE_ID) -eq $num_objects_expected ]] for ((i = 0; i < $num_objects_expected; i++)); do - rados -p rbd stat rbd_data.$IMAGE_ID.$(printf %016x $i) | grep "size $((OBJECT_SIZE / 2))" + rados -p rbd stat rbd_data.$IMAGE_ID.$(printf %016x $i) | egrep "(size $((OBJECT_SIZE / 2)))|(size 0)" done } @@ -107,7 +104,7 @@ assert_deallocated # unaligned blkdev_issue_discard allocate py_blkdiscard $((OBJECT_SIZE / 2)) -assert_deallocated_unaligned 1 +assert_deallocated_unaligned $NUM_OBJECTS # unaligned blkdev_issue_zeroout w/ BLKDEV_ZERO_NOUNMAP allocate diff --git a/ceph/qa/workunits/rbd/krbd_udev_enumerate.sh b/ceph/qa/workunits/rbd/krbd_udev_enumerate.sh new file mode 100755 index 000000000..494f958f8 --- /dev/null +++ b/ceph/qa/workunits/rbd/krbd_udev_enumerate.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash + +# This is a test for https://tracker.ceph.com/issues/41036, but it also +# triggers https://tracker.ceph.com/issues/41404 in some environments. + +set -ex + +function assert_exit_codes() { + declare -a pids=($@) + + for pid in ${pids[@]}; do + wait $pid + done +} + +function run_map() { + declare -a pids + + for i in {1..300}; do + sudo rbd map img$i & + pids+=($!) + done + + assert_exit_codes ${pids[@]} + [[ $(rbd showmapped | wc -l) -eq 301 ]] +} + +function run_unmap_by_dev() { + declare -a pids + + run_map + for i in {0..299}; do + sudo rbd unmap /dev/rbd$i & + pids+=($!) + done + + assert_exit_codes ${pids[@]} + [[ $(rbd showmapped | wc -l) -eq 0 ]] +} + +function run_unmap_by_spec() { + declare -a pids + + run_map + for i in {1..300}; do + sudo rbd unmap img$i & + pids+=($!) + done + + assert_exit_codes ${pids[@]} + [[ $(rbd showmapped | wc -l) -eq 0 ]] +} + +# Can't test with exclusive-lock, don't bother enabling deep-flatten. +# See https://tracker.ceph.com/issues/42492. +for i in {1..300}; do + rbd create --size 1 --image-feature '' img$i +done + +for i in {1..30}; do + echo Iteration $i + run_unmap_by_dev + run_unmap_by_spec +done + +echo OK diff --git a/ceph/qa/workunits/rbd/krbd_udev_netlink_enobufs.sh b/ceph/qa/workunits/rbd/krbd_udev_netlink_enobufs.sh new file mode 100755 index 000000000..7c9c53a2f --- /dev/null +++ b/ceph/qa/workunits/rbd/krbd_udev_netlink_enobufs.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# This is a test for https://tracker.ceph.com/issues/41404, verifying that udev +# events are properly reaped while the image is being (un)mapped in the kernel. +# UDEV_BUF_SIZE is 1M (giving us a 2M socket receive buffer), but modprobe + +# modprobe -r generate ~28M worth of "block" events. + +set -ex + +rbd create --size 1 img + +ceph osd pause +sudo rbd map img & +PID=$! +sudo modprobe scsi_debug max_luns=16 add_host=16 num_parts=1 num_tgts=16 +sudo udevadm settle +sudo modprobe -r scsi_debug +[[ $(rbd showmapped | wc -l) -eq 0 ]] +ceph osd unpause +wait $PID +[[ $(rbd showmapped | wc -l) -eq 2 ]] +sudo rbd unmap img + +echo OK diff --git a/ceph/qa/workunits/rbd/qemu-iotests.sh b/ceph/qa/workunits/rbd/qemu-iotests.sh index e775ade72..1cd9c4e00 100755 --- a/ceph/qa/workunits/rbd/qemu-iotests.sh +++ b/ceph/qa/workunits/rbd/qemu-iotests.sh @@ -9,13 +9,15 @@ testlist='001 002 003 004 005 008 009 010 011 021 025 032 033 055' git clone https://github.com/qemu/qemu.git cd qemu -if lsb_release -da | grep -iq xenial; then +if lsb_release -da 2>&1 | grep -iq 'bionic'; then + # Bionic requires a matching test harness + git checkout v2.11.0 +elif lsb_release -da 2>&1 | grep -iq 'xenial'; then # Xenial requires a recent test harness git checkout v2.3.0 else # use v2.2.0-rc3 (last released version that handles all the tests git checkout 2528043f1f299e0e88cb026f1ca7c40bbb4e1f80 - fi cd tests/qemu-iotests @@ -24,6 +26,12 @@ mkdir bin if [ -x '/usr/bin/qemu-system-x86_64' ] then QEMU='/usr/bin/qemu-system-x86_64' + + # Bionic (v2.11.0) tests expect all tools in current directory + ln -s $QEMU qemu + ln -s /usr/bin/qemu-img + ln -s /usr/bin/qemu-io + ln -s /usr/bin/qemu-nbd else QEMU='/usr/libexec/qemu-kvm' diff --git a/ceph/qa/workunits/rbd/rbd-nbd.sh b/ceph/qa/workunits/rbd/rbd-nbd.sh index 524f8bd3f..9ea6e3d33 100755 --- a/ceph/qa/workunits/rbd/rbd-nbd.sh +++ b/ceph/qa/workunits/rbd/rbd-nbd.sh @@ -64,6 +64,7 @@ function cleanup() sleep $s rbd -p ${POOL} status ${IMAGE} | grep 'Watchers: none' && break done + rbd -p ${POOL} snap purge ${IMAGE} rbd -p ${POOL} remove ${IMAGE} fi } @@ -73,6 +74,27 @@ function expect_false() if "$@"; then return 1; else return 0; fi } +function get_pid() +{ + PID=$(rbd-nbd --format xml list-mapped | $XMLSTARLET sel -t -v \ + "//devices/device[pool='${POOL}'][image='${IMAGE}'][device='${DEV}']/id") + test -n "${PID}" + ps -p ${PID} -o cmd | grep rbd-nbd +} + +unmap_device() +{ + local unmap_dev=$1 + local list_dev=$2 + _sudo rbd-nbd unmap ${unmap_dev} + + for s in 0.5 1 2 4 8 16 32; do + sleep ${s} + rbd-nbd list-mapped | expect_false grep "${list_dev} $" && return 0 + done + return 1 +} + # # main # @@ -89,26 +111,24 @@ fi expect_false _sudo rbd-nbd map INVALIDIMAGE expect_false _sudo rbd-nbd --device INVALIDDEV map ${IMAGE} +# list format test +expect_false rbd-nbd --format INVALID list-mapped +rbd-nbd --format json --pretty-format list-mapped +rbd-nbd --format xml list-mapped + # map test using the first unused device DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}` -PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \ - '$2 == pool && $3 == img && $5 == dev {print $1}') -test -n "${PID}" -ps -p ${PID} -o cmd | grep rbd-nbd +get_pid # map test specifying the device expect_false _sudo rbd-nbd --device ${DEV} map ${POOL}/${IMAGE} dev1=${DEV} -_sudo rbd-nbd unmap ${DEV} -rbd-nbd list-mapped | expect_false grep "${DEV} $" +unmap_device ${DEV} ${DEV} DEV= # XXX: race possible when the device is reused by other process DEV=`_sudo rbd-nbd --device ${dev1} map ${POOL}/${IMAGE}` [ "${DEV}" = "${dev1}" ] rbd-nbd list-mapped | grep "${IMAGE}" -PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \ - '$2 == pool && $3 == img && $5 == dev {print $1}') -test -n "${PID}" -ps -p ${PID} -o cmd | grep rbd-nbd +get_pid # read test [ "`dd if=${DATA} bs=1M | md5sum`" = "`_sudo dd if=${DEV} bs=1M | md5sum`" ] @@ -160,22 +180,34 @@ _sudo rbd-nbd unmap ${DEV} # exclusive option test DEV=`_sudo rbd-nbd map --exclusive ${POOL}/${IMAGE}` -PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \ - '$2 == pool && $3 == img && $5 == dev {print $1}') -test -n "${PID}" -ps -p ${PID} -o cmd | grep rbd-nbd +get_pid _sudo dd if=${DATA} of=${DEV} bs=1M oflag=direct expect_false timeout 10 \ rbd bench ${IMAGE} --io-type write --io-size=1024 --io-total=1024 _sudo rbd-nbd unmap ${DEV} +DEV= +rbd bench ${IMAGE} --io-type write --io-size=1024 --io-total=1024 + +# unmap by image name test +DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}` +get_pid +_sudo rbd-nbd unmap "${IMAGE}" +rbd-nbd list-mapped | expect_false grep "${DEV} $" +DEV= +ps -p ${PID} -o cmd | expect_false grep rbd-nbd + +# map/unmap snap test +rbd snap create ${POOL}/${IMAGE}@snap +DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}@snap` +get_pid +unmap_device "${IMAGE}@snap" ${DEV} +DEV= +ps -p ${PID} -o cmd | expect_false grep rbd-nbd # auto unmap test DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}` -PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \ - '$2 == pool && $3 == img && $5 == dev {print $1}') -test -n "${PID}" -ps -p ${PID} -o cmd | grep rbd-nbd +get_pid _sudo kill ${PID} for i in `seq 10`; do rbd-nbd list-mapped | expect_false grep "^${PID} *${POOL} *${IMAGE}" && break @@ -183,7 +215,4 @@ for i in `seq 10`; do done rbd-nbd list-mapped | expect_false grep "^${PID} *${POOL} *${IMAGE}" -DEV= -rbd bench ${IMAGE} --io-type write --io-size=1024 --io-total=1024 - echo OK diff --git a/ceph/qa/workunits/rbd/rbd_mirror.sh b/ceph/qa/workunits/rbd/rbd_mirror.sh index c2308c355..60d11e7cc 100755 --- a/ceph/qa/workunits/rbd/rbd_mirror.sh +++ b/ceph/qa/workunits/rbd/rbd_mirror.sh @@ -127,6 +127,13 @@ wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${new_name} 'up+replaying' rename_image ${CLUSTER2} ${POOL} ${new_name} ${image} wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} +testlog "TEST: test trash move restore" +image_id=$(get_image_id ${CLUSTER2} ${POOL} ${image}) +trash_move ${CLUSTER2} ${POOL} ${image} +wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' +trash_restore ${CLUSTER2} ${POOL} ${image_id} +wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} + testlog "TEST: failover and failback" start_mirror ${CLUSTER2} diff --git a/ceph/qa/workunits/rbd/rbd_mirror_helpers.sh b/ceph/qa/workunits/rbd/rbd_mirror_helpers.sh index 1e086eee3..8270d1ea8 100755 --- a/ceph/qa/workunits/rbd/rbd_mirror_helpers.sh +++ b/ceph/qa/workunits/rbd/rbd_mirror_helpers.sh @@ -64,6 +64,15 @@ # ../qa/workunits/rbd/rbd_mirror.sh cleanup # +if type xmlstarlet > /dev/null 2>&1; then + XMLSTARLET=xmlstarlet +elif type xml > /dev/null 2>&1; then + XMLSTARLET=xml +else + echo "Missing xmlstarlet binary!" + exit 1 +fi + CLUSTER1=cluster1 CLUSTER2=cluster2 POOL=mirror @@ -246,15 +255,15 @@ cleanup() done done + CEPH_ARGS='' ceph --cluster ${CLUSTER1} osd pool rm ${POOL} ${POOL} --yes-i-really-really-mean-it + CEPH_ARGS='' ceph --cluster ${CLUSTER2} osd pool rm ${POOL} ${POOL} --yes-i-really-really-mean-it + CEPH_ARGS='' ceph --cluster ${CLUSTER1} osd pool rm ${PARENT_POOL} ${PARENT_POOL} --yes-i-really-really-mean-it + CEPH_ARGS='' ceph --cluster ${CLUSTER2} osd pool rm ${PARENT_POOL} ${PARENT_POOL} --yes-i-really-really-mean-it + if [ -z "${RBD_MIRROR_USE_EXISTING_CLUSTER}" ]; then cd ${CEPH_ROOT} CEPH_ARGS='' ${CEPH_SRC}/mstop.sh ${CLUSTER1} CEPH_ARGS='' ${CEPH_SRC}/mstop.sh ${CLUSTER2} - else - CEPH_ARGS='' ceph --cluster ${CLUSTER1} osd pool rm ${POOL} ${POOL} --yes-i-really-really-mean-it - CEPH_ARGS='' ceph --cluster ${CLUSTER2} osd pool rm ${POOL} ${POOL} --yes-i-really-really-mean-it - CEPH_ARGS='' ceph --cluster ${CLUSTER1} osd pool rm ${PARENT_POOL} ${PARENT_POOL} --yes-i-really-really-mean-it - CEPH_ARGS='' ceph --cluster ${CLUSTER2} osd pool rm ${PARENT_POOL} ${PARENT_POOL} --yes-i-really-really-mean-it fi test "${RBD_MIRROR_TEMDIR}" = "${TEMPDIR}" || rm -Rf ${TEMPDIR} @@ -544,11 +553,44 @@ test_status_in_pool_dir() local state_pattern=$4 local description_pattern=$5 - local status_log=${TEMPDIR}/${cluster}-${image}.mirror_status + local status_log=${TEMPDIR}/${cluster}-${pool}-${image}.mirror_status rbd --cluster ${cluster} -p ${pool} mirror image status ${image} | tee ${status_log} >&2 grep "state: .*${state_pattern}" ${status_log} || return 1 grep "description: .*${description_pattern}" ${status_log} || return 1 + + # recheck using `mirror pool status` command to stress test it. + + local last_update="$(sed -nEe 's/^ *last_update: *(.*) *$/\1/p' ${status_log})" + test_mirror_pool_status_verbose \ + ${cluster} ${pool} ${image} "${state_pattern}" "${last_update}" && + return 0 + + echo "'mirror pool status' test failed" >&2 + exit 1 +} + +test_mirror_pool_status_verbose() +{ + local cluster=$1 + local pool=$2 + local image=$3 + local state_pattern="$4" + local prev_last_update="$5" + + local status_log=${TEMPDIR}/${cluster}-${pool}.mirror_status + + rbd --cluster ${cluster} mirror pool status ${pool} --verbose --format xml \ + > ${status_log} + + local last_update state + last_update=$($XMLSTARLET sel -t -v \ + "//images/image[name='${image}']/last_update" < ${status_log}) + state=$($XMLSTARLET sel -t -v \ + "//images/image[name='${image}']/state" < ${status_log}) + + echo "${state}" | grep "${state_pattern}" || + test "${last_update}" '>' "${prev_last_update}" } wait_for_status_in_pool_dir() @@ -637,6 +679,22 @@ remove_image_retry() return 1 } +trash_move() { + local cluster=$1 + local pool=$2 + local image=$3 + + rbd --cluster=${cluster} -p ${pool} trash move ${image} +} + +trash_restore() { + local cluster=$1 + local pool=$2 + local image_id=$3 + + rbd --cluster=${cluster} -p ${pool} trash restore ${image_id} +} + clone_image() { local cluster=$1 diff --git a/ceph/qa/workunits/rbd/run_devstack_tempest.sh b/ceph/qa/workunits/rbd/run_devstack_tempest.sh index 65a45d8b7..9f141b200 100755 --- a/ceph/qa/workunits/rbd/run_devstack_tempest.sh +++ b/ceph/qa/workunits/rbd/run_devstack_tempest.sh @@ -87,8 +87,8 @@ CINDER_ENABLED_BACKENDS=ceph:ceph TEMPEST_STORAGE_PROTOCOL=ceph REMOTE_CEPH=True -enable_plugin devstack-plugin-mariadb git://github.com/openstack/devstack-plugin-mariadb -enable_plugin devstack-plugin-ceph git://git.openstack.org/openstack/devstack-plugin-ceph +enable_plugin devstack-plugin-mariadb https://github.com/openstack/devstack-plugin-mariadb +enable_plugin devstack-plugin-ceph https://git.openstack.org/openstack/devstack-plugin-ceph EOF cat< ${STACK_HOME_PATH}/start.sh diff --git a/ceph/run-make-check.sh b/ceph/run-make-check.sh index 2244e5ea5..b5679e4e1 100755 --- a/ceph/run-make-check.sh +++ b/ceph/run-make-check.sh @@ -89,7 +89,7 @@ function run() { fi if test -f ./install-deps.sh ; then - $DRY_RUN ./install-deps.sh || return 1 + $DRY_RUN source ./install-deps.sh || return 1 trap clean_up_after_myself EXIT fi diff --git a/ceph/src/.git_version b/ceph/src/.git_version index 63186701d..67e364a28 100644 --- a/ceph/src/.git_version +++ b/ceph/src/.git_version @@ -1,2 +1,2 @@ -1436006594665279fe734b4c15d7e08c13ebd777 -v12.2.12 +584a20eb0237c657dc0567da126be145106aa47e +v12.2.13 diff --git a/ceph/src/CMakeLists.txt b/ceph/src/CMakeLists.txt index 4ff19154f..f54bbd3dd 100644 --- a/ceph/src/CMakeLists.txt +++ b/ceph/src/CMakeLists.txt @@ -245,20 +245,15 @@ endif() # Python stuff find_package(PythonInterp 2 REQUIRED) -find_package(PythonLibs 2 REQUIRED) +find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT REQUIRED) -option(WITH_PYTHON3 "build python3 bindings" "CHECK") -if(WITH_PYTHON3 MATCHES "check|CHECK") - find_package(Python3Interp 3 QUIET) - find_package(Python3Libs 3 QUIET) - if(PYTHON3INTERP_FOUND AND PYTHON3LIBS_FOUND) - set(WITH_PYTHON3 ON) - else() - set(WITH_PYTHON3 OFF) +option(WITH_PYTHON3 "build python3 bindings" ON) +if(WITH_PYTHON3) + if(WITH_PYTHON3 MATCHES "^(1|ON|YES|TRUE|Y)$") + set(WITH_PYTHON3 "3") endif() -elseif(WITH_PYTHON3) - find_package(Python3Interp 3 REQUIRED) - find_package(Python3Libs 3 REQUIRED) + find_package(Python3Interp ${WITH_PYTHON3} REQUIRED) + find_package(Python3Libs ${PYTHON3_VERSION_STRING} EXACT REQUIRED) endif() if(HAVE_XIO) diff --git a/ceph/src/auth/KeyRing.cc b/ceph/src/auth/KeyRing.cc index b946a298b..22d8dead2 100644 --- a/ceph/src/auth/KeyRing.cc +++ b/ceph/src/auth/KeyRing.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include "auth/KeyRing.h" #include "common/config.h" #include "common/debug.h" @@ -256,6 +257,7 @@ void KeyRing::print(ostream& out) bufferlist::iterator dataiter = q->second.begin(); string caps; ::decode(caps, dataiter); + boost::replace_all(caps, "\"", "\\\""); out << "\tcaps " << q->first << " = \"" << caps << '"' << std::endl; } } diff --git a/ceph/src/ceph-detect-init/ceph_detect_init/__init__.py b/ceph/src/ceph-detect-init/ceph_detect_init/__init__.py index fe0a2a787..b8ac387d0 100644 --- a/ceph/src/ceph-detect-init/ceph_detect_init/__init__.py +++ b/ceph/src/ceph-detect-init/ceph_detect_init/__init__.py @@ -28,6 +28,7 @@ from ceph_detect_init import oraclevms import os import logging import platform +import re def get(use_rhceph=False): @@ -87,11 +88,11 @@ def _get_distro(distro, use_rhceph=False): def _normalized_distro_name(distro): distro = distro.lower() - if distro.startswith(('redhat', 'red hat')): + if distro.startswith(('redhat', 'red hat', 'rhel')): return 'redhat' elif distro.startswith(('scientific', 'scientific linux')): return 'scientific' - elif distro.startswith(('suse', 'opensuse')): + elif distro.startswith(('suse', 'opensuse', 'sles', 'sled')): return 'suse' elif distro.startswith('centos'): return 'centos' @@ -106,6 +107,15 @@ def _normalized_distro_name(distro): return distro +def _extract_from_os_release(file_contents, key): + r = re.compile('^{}\=[\'\"]*([^\'\"\n]*)'.format(key), re.MULTILINE) + match = r.search(file_contents) + if match: + return match.group(1) + else: + return '' + + def platform_information(): """detect platform information from remote host.""" try: @@ -123,10 +133,23 @@ def platform_information(): return ('docker', 'docker', 'docker') if platform.system() == 'Linux': - linux_distro = platform.linux_distribution( - supported_dists=platform._supported_dists + ('alpine', 'arch')) - logging.debug('platform_information: linux_distribution = ' + - str(linux_distro)) + linux_distro = ('', '', '') + if os.path.isfile('/etc/os-release'): + try: + with open('/etc/os-release', 'r') as f: + data = f.read() + linux_distro = ( + _extract_from_os_release(data, 'ID'), + _extract_from_os_release(data, 'VERSION_ID'), + '') + except Exception as err: + logging.debug("platform_information: ", + "Error while opening %s : %s" % (file_name, err)) + else: + linux_distro = platform.linux_distribution( + supported_dists=platform._supported_dists + ('alpine', 'arch')) + logging.debug('platform_information: linux_distribution = ' + + str(linux_distro)) distro, release, codename = linux_distro elif platform.system() == 'FreeBSD': distro = 'freebsd' diff --git a/ceph/src/ceph-detect-init/tests/test_all.py b/ceph/src/ceph-detect-init/tests/test_all.py index 18451bf46..dfdf16b2c 100644 --- a/ceph/src/ceph-detect-init/tests/test_all.py +++ b/ceph/src/ceph-detect-init/tests/test_all.py @@ -165,6 +165,7 @@ class TestCephDetectInit(testtools.TestCase): is_openrc=(lambda: False)): self.assertEqual('unknown', gentoo.choose_init()) + @mock.patch('os.path.isfile', lambda path: False) def test_get(self): with mock.patch.multiple( 'platform', @@ -252,6 +253,7 @@ class TestCephDetectInit(testtools.TestCase): self.assertEqual('gentoo', n('exherbo')) self.assertEqual('virtuozzo', n('Virtuozzo Linux')) + @mock.patch('os.path.isfile', lambda path: False) @mock.patch('platform.system', lambda: 'Linux') def test_platform_information_linux(self): with mock.patch('platform.linux_distribution', @@ -319,6 +321,9 @@ class TestCephDetectInit(testtools.TestCase): argv = ['--use-rhceph', '--verbose'] self.assertEqual(0, main.run(argv)) + @mock.patch('os.path.isfile', lambda path: False) + def test_run_unknown_distro(self): + argv = ['--use-rhceph', '--verbose'] with mock.patch.multiple( 'platform', system=lambda: 'Linux', @@ -326,6 +331,222 @@ class TestCephDetectInit(testtools.TestCase): self.assertRaises(exc.UnsupportedPlatform, main.run, argv) self.assertEqual(0, main.run(argv + ['--default=sysvinit'])) + def test_extract_from_os_release(self): + self.assertEqual('', ceph_detect_init._extract_from_os_release( + 'bad data', 'ID')) + os_release_centos_7 = """ +NAME="CentOS Linux" +VERSION="7 (Core)" +ID="centos" +ID_LIKE="rhel fedora" +VERSION_ID="7" +PRETTY_NAME="CentOS Linux 7 (Core)" +ANSI_COLOR="0;31" +CPE_NAME="cpe:/o:centos:centos:7" +HOME_URL="https://www.centos.org/" +BUG_REPORT_URL="https://bugs.centos.org/" + +CENTOS_MANTISBT_PROJECT="CentOS-7" +CENTOS_MANTISBT_PROJECT_VERSION="7" +REDHAT_SUPPORT_PRODUCT="centos" +REDHAT_SUPPORT_PRODUCT_VERSION="7" +""" + self.assertEqual('centos', ceph_detect_init._extract_from_os_release( + os_release_centos_7, 'ID')) + self.assertEqual('7', ceph_detect_init._extract_from_os_release( + os_release_centos_7, 'VERSION_ID')) + os_release_debian_stretch = """ +PRETTY_NAME="Debian GNU/Linux 9 (stretch)" +NAME="Debian GNU/Linux" +VERSION_ID="9" +VERSION="9 (stretch)" +ID=debian +HOME_URL="https://www.debian.org/" +SUPPORT_URL="https://www.debian.org/support" +BUG_REPORT_URL="https://bugs.debian.org/" +""" + self.assertEqual('debian', ceph_detect_init._extract_from_os_release( + os_release_debian_stretch, 'ID')) + self.assertEqual('9', ceph_detect_init._extract_from_os_release( + os_release_debian_stretch, 'VERSION_ID')) + os_release_fedora_26 = """ +NAME=Fedora +VERSION="26 (Twenty Six)" +ID=fedora +VERSION_ID=26 +PRETTY_NAME="Fedora 26 (Twenty Six)" +ANSI_COLOR="0;34" +CPE_NAME="cpe:/o:fedoraproject:fedora:26" +HOME_URL="https://fedoraproject.org/" +BUG_REPORT_URL="https://bugzilla.redhat.com/" +REDHAT_BUGZILLA_PRODUCT="Fedora" +REDHAT_BUGZILLA_PRODUCT_VERSION=26 +REDHAT_SUPPORT_PRODUCT="Fedora" +REDHAT_SUPPORT_PRODUCT_VERSION=26 +PRIVACY_POLICY_URL=https://fedoraproject.org/wiki/Legal:PrivacyPolicy +""" + self.assertEqual('fedora', ceph_detect_init._extract_from_os_release( + os_release_fedora_26, 'ID')) + self.assertEqual('26', ceph_detect_init._extract_from_os_release( + os_release_fedora_26, 'VERSION_ID')) + os_release_opensuse_42_2 = """ +NAME="openSUSE Leap" +VERSION="42.2" +ID=opensuse +ID_LIKE="suse" +VERSION_ID="42.2" +PRETTY_NAME="openSUSE Leap 42.2" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:opensuse:leap:42.2" +BUG_REPORT_URL="https://bugs.opensuse.org" +HOME_URL="https://www.opensuse.org/" +""" + self.assertEqual('opensuse', ceph_detect_init._extract_from_os_release( + os_release_opensuse_42_2, 'ID')) + self.assertEqual('42.2', ceph_detect_init._extract_from_os_release( + os_release_opensuse_42_2, 'VERSION_ID')) + os_release_opensuse_42_3 = """ +NAME="openSUSE Leap" +VERSION="42.3" +ID=opensuse +ID_LIKE="suse" +VERSION_ID="42.3" +PRETTY_NAME="openSUSE Leap 42.3" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:opensuse:leap:42.3" +BUG_REPORT_URL="https://bugs.opensuse.org" +HOME_URL="https://www.opensuse.org/" +""" + self.assertEqual('opensuse', ceph_detect_init._extract_from_os_release( + os_release_opensuse_42_3, 'ID')) + self.assertEqual('42.3', ceph_detect_init._extract_from_os_release( + os_release_opensuse_42_3, 'VERSION_ID')) + os_release_opensuse_15_0 = """ +NAME="openSUSE Leap" +VERSION="15.0" +ID="opensuse-leap" +ID_LIKE="suse opensuse" +VERSION_ID="15.0" +PRETTY_NAME="openSUSE Leap 15.0" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:opensuse:leap:15.0" +BUG_REPORT_URL="https://bugs.opensuse.org" +HOME_URL="https://www.opensuse.org/" +""" + self.assertEqual('opensuse-leap', + ceph_detect_init._extract_from_os_release( + os_release_opensuse_15_0, 'ID')) + self.assertEqual('15.0', ceph_detect_init._extract_from_os_release( + os_release_opensuse_15_0, 'VERSION_ID')) + os_release_sles_12_3 = """ +NAME="SLES" +VERSION="12-SP3" +VERSION_ID="12.3" +PRETTY_NAME="SUSE Linux Enterprise Server 12 SP3" +ID="sles" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:suse:sles:12:sp3" +""" + self.assertEqual('sles', ceph_detect_init._extract_from_os_release( + os_release_sles_12_3, 'ID')) + self.assertEqual('12.3', ceph_detect_init._extract_from_os_release( + os_release_sles_12_3, 'VERSION_ID')) + os_release_sled_15 = """ +NAME="SLED" +VERSION="15" +VERSION_ID="15" +PRETTY_NAME="SUSE Linux Enterprise Desktop 15" +ID="sled" +ID_LIKE="suse" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:suse:sled:15" +""" + self.assertEqual('sled', ceph_detect_init._extract_from_os_release( + os_release_sled_15, 'ID')) + self.assertEqual('15', ceph_detect_init._extract_from_os_release( + os_release_sled_15, 'VERSION_ID')) + os_release_sles_15 = """ +NAME="SLES" +VERSION="15" +VERSION_ID="15" +PRETTY_NAME="SUSE Linux Enterprise Server 15" +ID="sles" +ID_LIKE="suse" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:suse:sles:15" +""" + self.assertEqual('sles', ceph_detect_init._extract_from_os_release( + os_release_sles_15, 'ID')) + self.assertEqual('15', ceph_detect_init._extract_from_os_release( + os_release_sles_15, 'VERSION_ID')) + os_release_opensuse_tumbleweed_old_style = """ +NAME="openSUSE Tumbleweed" +# VERSION="20170502" +ID=opensuse +ID_LIKE="suse" +VERSION_ID="20170502" +PRETTY_NAME="openSUSE Tumbleweed" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:opensuse:tumbleweed:20170502" +BUG_REPORT_URL="https://bugs.opensuse.org" +HOME_URL="https://www.opensuse.org/" +""" + self.assertEqual('opensuse', + ceph_detect_init._extract_from_os_release( + os_release_opensuse_tumbleweed_old_style, 'ID')) + self.assertEqual('20170502', ceph_detect_init._extract_from_os_release( + os_release_opensuse_tumbleweed_old_style, + 'VERSION_ID')) + os_release_opensuse_tumbleweed_new_style = """ +NAME="openSUSE Tumbleweed" +# VERSION="20180712" +ID="opensuse-tumbleweed" +ID_LIKE="opensuse suse" +VERSION_ID="20180712" +PRETTY_NAME="openSUSE Tumbleweed" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:opensuse:tumbleweed:20180712" +BUG_REPORT_URL="https://bugs.opensuse.org" +HOME_URL="https://www.opensuse.org/" +""" + self.assertEqual('opensuse-tumbleweed', + ceph_detect_init._extract_from_os_release( + os_release_opensuse_tumbleweed_new_style, 'ID')) + self.assertEqual('20180712', ceph_detect_init._extract_from_os_release( + os_release_opensuse_tumbleweed_new_style, + 'VERSION_ID')) + os_release_ubuntu_xenial = """ +NAME="Ubuntu" +VERSION="16.04 LTS (Xenial Xerus)" +ID=ubuntu +ID_LIKE=debian +PRETTY_NAME="Ubuntu 16.04 LTS" +VERSION_ID="16.04" +HOME_URL="http://www.ubuntu.com/" +SUPPORT_URL="http://help.ubuntu.com/" +BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" +UBUNTU_CODENAME=xenial +""" + self.assertEqual('ubuntu', ceph_detect_init._extract_from_os_release( + os_release_ubuntu_xenial, 'ID')) + self.assertEqual('16.04', ceph_detect_init._extract_from_os_release( + os_release_ubuntu_xenial, 'VERSION_ID')) + os_release_ubuntu_trusty = """ +NAME="Ubuntu" +VERSION="14.04.4 LTS, Trusty Tahr" +ID=ubuntu +ID_LIKE=debian +PRETTY_NAME="Ubuntu 14.04.4 LTS" +VERSION_ID="14.04" +HOME_URL="http://www.ubuntu.com/" +SUPPORT_URL="http://help.ubuntu.com/" +BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" +""" + self.assertEqual('ubuntu', ceph_detect_init._extract_from_os_release( + os_release_ubuntu_trusty, 'ID')) + self.assertEqual('14.04', ceph_detect_init._extract_from_os_release( + os_release_ubuntu_trusty, 'VERSION_ID')) + # Local Variables: # compile-command: "cd .. ; .tox/py27/bin/py.test tests/test_all.py" # End: diff --git a/ceph/src/ceph-detect-init/tox.ini b/ceph/src/ceph-detect-init/tox.ini index 54691f78d..16bad69c4 100644 --- a/ceph/src/ceph-detect-init/tox.ini +++ b/ceph/src/ceph-detect-init/tox.ini @@ -1,11 +1,10 @@ [tox] -envlist = pep8,py27,py3 +envlist = pep8,py27 skip_missing_interpreters = True [testenv] basepython = py27: python2.7 - py3: python3 setenv = VIRTUAL_ENV={envdir} usedevelop = true deps = diff --git a/ceph/src/ceph-volume/ceph_volume/api/lvm.py b/ceph/src/ceph-volume/ceph_volume/api/lvm.py index bcb54d65b..949d61425 100644 --- a/ceph/src/ceph-volume/ceph_volume/api/lvm.py +++ b/ceph/src/ceph-volume/ceph_volume/api/lvm.py @@ -67,8 +67,13 @@ def _splitname_parser(line): :returns: dictionary with stripped prefixes """ - parts = line[0].split(';') parsed = {} + try: + parts = line[0].split(';') + except IndexError: + logger.exception('Unable to parse mapper device: %s', line) + return parsed + for part in parts: part = part.replace("'", '') key, value = part.split('=') @@ -359,7 +364,7 @@ def get_lv_from_argument(argument): return get_lv(lv_name=lv_name, vg_name=vg_name) -def get_lv(lv_name=None, vg_name=None, lv_path=None, lv_uuid=None, lv_tags=None): +def get_lv(lv_name=None, vg_name=None, lv_path=None, lv_uuid=None, lv_tags=None, lvs=None): """ Return a matching lv for the current system, requiring ``lv_name``, ``vg_name``, ``lv_path`` or ``tags``. Raises an error if more than one lv @@ -371,7 +376,8 @@ def get_lv(lv_name=None, vg_name=None, lv_path=None, lv_uuid=None, lv_tags=None) """ if not any([lv_name, vg_name, lv_path, lv_uuid, lv_tags]): return None - lvs = Volumes() + if lvs is None: + lvs = Volumes() return lvs.get( lv_name=lv_name, vg_name=vg_name, lv_path=lv_path, lv_uuid=lv_uuid, lv_tags=lv_tags diff --git a/ceph/src/ceph-volume/ceph_volume/configuration.py b/ceph/src/ceph-volume/ceph_volume/configuration.py index 6379ef67a..2fee47ffa 100644 --- a/ceph/src/ceph-volume/ceph_volume/configuration.py +++ b/ceph/src/ceph-volume/ceph_volume/configuration.py @@ -1,13 +1,19 @@ -try: - import configparser -except ImportError: - import ConfigParser as configparser import contextlib import logging import os import re from ceph_volume import terminal, conf from ceph_volume import exceptions +from sys import version_info as sys_version_info + +if sys_version_info.major >= 3: + import configparser + conf_parentclass = configparser.ConfigParser +elif sys_version_info.major < 3: + import ConfigParser as configparser + conf_parentclass = configparser.SafeConfigParser +else: + raise RuntimeError('Not expecting python version > 3 yet.') logger = logging.getLogger(__name__) @@ -50,7 +56,7 @@ def load(abspath=None): ceph_file = open(abspath) trimmed_conf = _TrimIndentFile(ceph_file) with contextlib.closing(ceph_file): - parser.readfp(trimmed_conf) + parser.read_conf(trimmed_conf) conf.ceph = parser return parser except configparser.ParsingError as error: @@ -59,9 +65,9 @@ def load(abspath=None): raise RuntimeError('Unable to read configuration file: %s' % abspath) -class Conf(configparser.SafeConfigParser): +class Conf(conf_parentclass): """ - Subclasses from SafeConfigParser to give a few helpers for Ceph + Subclasses from ConfigParser to give a few helpers for Ceph configuration. """ @@ -215,3 +221,11 @@ class Conf(configparser.SafeConfigParser): for name, val in options.items(): if isinstance(val, list): options[name] = '\n'.join(val) + + def read_conf(self, conffile): + if sys_version_info.major >= 3: + self.read_file(conffile) + elif sys_version_info.major < 3: + self.readfp(conffile) + else: + raise RuntimeError('Not expecting python version > 3 yet.') diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py index 1ad15bc80..2ff5a0943 100644 --- a/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py @@ -109,14 +109,16 @@ def get_osd_device_path(osd_lv, lvs, device_type, dmcrypt_secret=None): encryption_utils.luks_open(dmcrypt_secret, device_lv.lv_path, device_uuid) return '/dev/mapper/%s' % device_uuid return device_lv.lv_path - else: - # this could be a regular device, so query it with blkid - physical_device = disk.get_device_from_partuuid(device_uuid) - if physical_device and is_encrypted: + + # this could be a regular device, so query it with blkid + physical_device = disk.get_device_from_partuuid(device_uuid) + if physical_device: + if is_encrypted: encryption_utils.luks_open(dmcrypt_secret, physical_device, device_uuid) return '/dev/mapper/%s' % device_uuid - return physical_device or None - return None + return physical_device + + raise RuntimeError('could not find %s with uuid %s' % (device_type, device_uuid)) def activate_bluestore(lvs, no_systemd=False): diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/batch.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/batch.py index 76a52f37d..937099c30 100644 --- a/ceph/src/ceph-volume/ceph_volume/devices/lvm/batch.py +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/batch.py @@ -31,7 +31,7 @@ def bluestore_single_type(device_facts): Detect devices that are just HDDs or solid state so that a 1:1 device-to-osd provisioning can be done """ - types = [device.sys_api['rotational'] for device in device_facts] + types = [device.rotational for device in device_facts] if len(set(types)) == 1: return strategies.bluestore.SingleType @@ -41,7 +41,7 @@ def bluestore_mixed_type(device_facts): Detect if devices are HDDs as well as solid state so that block.db can be placed in solid devices while data is kept in the spinning drives. """ - types = [device.sys_api['rotational'] for device in device_facts] + types = [device.rotational for device in device_facts] if len(set(types)) > 1: return strategies.bluestore.MixedType @@ -51,7 +51,7 @@ def filestore_single_type(device_facts): Detect devices that are just HDDs or solid state so that a 1:1 device-to-osd provisioning can be done, keeping the journal on the OSD """ - types = [device.sys_api['rotational'] for device in device_facts] + types = [device.rotational for device in device_facts] if len(set(types)) == 1: return strategies.filestore.SingleType @@ -61,7 +61,7 @@ def filestore_mixed_type(device_facts): Detect if devices are HDDs as well as solid state so that the journal can be placed in solid devices while data is kept in the spinning drives. """ - types = [device.sys_api['rotational'] for device in device_facts] + types = [device.rotational for device in device_facts] if len(set(types)) > 1: return strategies.filestore.MixedType diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/listing.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/listing.py index a3975280d..affded335 100644 --- a/ceph/src/ceph-volume/ceph_volume/devices/lvm/listing.py +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/listing.py @@ -112,8 +112,8 @@ class List(object): def list(self, args): # ensure everything is up to date before calling out # to list lv's - self.update() - report = self.generate(args) + lvs = self.update() + report = self.generate(args, lvs) if args.format == 'json': # If the report is empty, we don't return a non-zero exit status # because it is assumed this is going to be consumed by automated @@ -153,25 +153,27 @@ class List(object): # this means that the device has changed, so it must be updated # on the API to reflect this lv.set_tags({device_name: disk_device}) + return lvs - def generate(self, args): + def generate(self, args, lvs=None): """ Generate reports for an individual device or for all Ceph-related devices, logical or physical, as long as they have been prepared by this tool before and contain enough metadata. """ if args.device: - return self.single_report(args.device) + return self.single_report(args.device, lvs) else: - return self.full_report() + return self.full_report(lvs) - def single_report(self, device): + def single_report(self, device, lvs=None): """ Generate a report for a single device. This can be either a logical volume in the form of vg/lv or a device with an absolute path like /dev/sda1 or /dev/sda """ - lvs = api.Volumes() + if lvs is None: + lvs = api.Volumes() report = {} lv = api.get_lv_from_argument(device) @@ -228,6 +230,7 @@ class List(object): if lvs is None: lvs = api.Volumes() report = {} + for lv in lvs: try: _id = lv.tags['ceph.osd_id'] @@ -247,7 +250,7 @@ class List(object): # bluestore will not have a journal, filestore will not have # a block/wal/db, so we must skip if not present continue - if not api.get_lv(lv_uuid=device_uuid): + if not api.get_lv(lv_uuid=device_uuid, lvs=lvs): # means we have a regular device, so query blkid disk_device = disk.get_device_from_partuuid(device_uuid) if disk_device: diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/strategies/strategies.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/strategies/strategies.py index d4ec5a730..db706a037 100644 --- a/ceph/src/ceph-volume/ceph_volume/devices/lvm/strategies/strategies.py +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/strategies/strategies.py @@ -6,8 +6,8 @@ class Strategy(object): self.args = args self.osds_per_device = args.osds_per_device self.devices = devices - self.hdds = [device for device in devices if device.sys_api['rotational'] == '1'] - self.ssds = [device for device in devices if device.sys_api['rotational'] == '0'] + self.hdds = [device for device in devices if device.rotational] + self.ssds = [device for device in devices if not device.rotational] self.computed = {'osds': [], 'vgs': [], 'filtered_devices': args.filtered_devices} def validate_compute(self): diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/zap.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/zap.py index 328a03615..bca32ac88 100644 --- a/ceph/src/ceph-volume/ceph_volume/devices/lvm/zap.py +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/zap.py @@ -1,12 +1,13 @@ import argparse import os import logging +import time from textwrap import dedent from ceph_volume import decorators, terminal, process from ceph_volume.api import lvm as api -from ceph_volume.util import system, encryption, disk, arg_validators +from ceph_volume.util import system, encryption, disk, arg_validators, str_to_int from ceph_volume.util.device import Device from ceph_volume.systemd import systemctl @@ -17,12 +18,38 @@ mlogger = terminal.MultiLogger(__name__) def wipefs(path): """ Removes the filesystem from an lv or partition. + + Environment variables supported:: + + * ``CEPH_VOLUME_WIPEFS_TRIES``: Defaults to 8 + * ``CEPH_VOLUME_WIPEFS_INTERVAL``: Defaults to 5 + """ - process.run([ - 'wipefs', - '--all', - path - ]) + tries = str_to_int( + os.environ.get('CEPH_VOLUME_WIPEFS_TRIES', 8) + ) + interval = str_to_int( + os.environ.get('CEPH_VOLUME_WIPEFS_INTERVAL', 5) + ) + + for trying in range(tries): + stdout, stderr, exit_code = process.call([ + 'wipefs', + '--all', + path + ]) + if exit_code != 0: + # this could narrow the retry by poking in the stderr of the output + # to verify that 'probing initialization failed' appears, but + # better to be broad in this retry to prevent missing on + # a different message that needs to be retried as well + terminal.warning( + 'failed to wipefs device, will try again to workaround probable race condition' + ) + time.sleep(interval) + else: + return + raise RuntimeError("could not complete wipefs on device: %s" % path) def zap_data(path): @@ -77,7 +104,7 @@ def ensure_associated_lvs(lvs): wal_lvs = lvs._filter(lv_tags={'ceph.type': 'wal'}) backing_devices = [ (journal_lvs, 'journal'), - (db_lvs, 'block'), + (db_lvs, 'db'), (wal_lvs, 'wal') ] @@ -243,8 +270,9 @@ class Zap(object): "Zapping successful for: %s" % ", ".join([str(d) for d in self.args.devices]) ) else: + identifier = self.args.osd_id or self.args.osd_fsid terminal.success( - "Zapping successful for OSD: %s" % self.args.osd_id or self.args.osd_fsid + "Zapping successful for OSD: %s" % identifier ) @decorators.needs_root diff --git a/ceph/src/ceph-volume/ceph_volume/devices/simple/activate.py b/ceph/src/ceph-volume/ceph_volume/devices/simple/activate.py index 3cf414fdc..bcc9645d6 100644 --- a/ceph/src/ceph-volume/ceph_volume/devices/simple/activate.py +++ b/ceph/src/ceph-volume/ceph_volume/devices/simple/activate.py @@ -35,8 +35,16 @@ class Activate(object): try: objectstore = json_config['type'] except KeyError: - logger.warning('"type" was not defined, will assume "bluestore"') - objectstore = 'bluestore' + if {'data', 'journal'}.issubset(set(devices)): + logger.warning( + '"type" key not found, assuming "filestore" since journal key is present' + ) + objectstore = 'filestore' + else: + logger.warning( + '"type" key not found, assuming "bluestore" since journal key is not present' + ) + objectstore = 'bluestore' # Go through all the device combinations that are absolutely required, # raise an error describing what was expected and what was found diff --git a/ceph/src/ceph-volume/ceph_volume/log.py b/ceph/src/ceph-volume/ceph_volume/log.py index 890b6da1b..802b5fec2 100644 --- a/ceph/src/ceph-volume/ceph_volume/log.py +++ b/ceph/src/ceph-volume/ceph_volume/log.py @@ -31,3 +31,18 @@ def setup(name='ceph-volume.log', log_path=None): fh.setFormatter(logging.Formatter(FILE_FORMAT)) root_logger.addHandler(fh) + + +def setup_console(): + # TODO: At some point ceph-volume should stop using the custom logger + # interface that exists in terminal.py and use the logging module to + # produce output for the terminal + # Console Logger + sh = logging.StreamHandler() + sh.setFormatter(logging.Formatter('[terminal] %(message)s')) + sh.setLevel(logging.DEBUG) + + terminal_logger = logging.getLogger('terminal') + + # allow all levels at root_logger, handlers control individual levels + terminal_logger.addHandler(sh) diff --git a/ceph/src/ceph-volume/ceph_volume/main.py b/ceph/src/ceph-volume/ceph_volume/main.py index 4685cb41c..f396daf00 100644 --- a/ceph/src/ceph-volume/ceph_volume/main.py +++ b/ceph/src/ceph-volume/ceph_volume/main.py @@ -131,6 +131,7 @@ Ceph Conf: {ceph_path} if os.path.isdir(conf.log_path): conf.log_path = os.path.join(args.log_path, 'ceph-volume.log') log.setup() + log.setup_console() logger = logging.getLogger(__name__) logger.info("Running command: ceph-volume %s %s", " ".join(main_args), " ".join(subcommand_args)) # set all variables from args and load everything needed according to diff --git a/ceph/src/ceph-volume/ceph_volume/terminal.py b/ceph/src/ceph-volume/ceph_volume/terminal.py index 23ce57e0e..a34946f92 100644 --- a/ceph/src/ceph-volume/ceph_volume/terminal.py +++ b/ceph/src/ceph-volume/ceph_volume/terminal.py @@ -2,6 +2,9 @@ import logging import sys +terminal_logger = logging.getLogger('terminal') + + class colorize(str): """ Pretty simple to use:: @@ -22,10 +25,9 @@ class colorize(str): """ def __init__(self, string): - self.stdout = sys.__stdout__ self.appends = '' self.prepends = '' - self.isatty = self.stdout.isatty() + self.isatty = sys.__stderr__.isatty() def _set_attributes(self): """ @@ -80,7 +82,9 @@ yellow_arrow = yellow('--> ') class _Write(object): def __init__(self, _writer=None, prefix='', suffix='', flush=False): - self._writer = _writer or sys.stdout + # we can't set sys.stderr as the default for _writer. otherwise + # pytest's capturing gets confused + self._writer = _writer or sys.stderr self.suffix = suffix self.prefix = prefix self.flush = flush @@ -94,9 +98,17 @@ class _Write(object): self.write(string) def write(self, line): - self._writer.write(self.prefix + line + self.suffix) - if self.flush: - self._writer.flush() + entry = self.prefix + line + self.suffix + + try: + self._writer.write(entry) + if self.flush: + self._writer.flush() + except (UnicodeDecodeError, UnicodeEncodeError): + try: + terminal_logger.info(entry.strip('\n')) + except (AttributeError, TypeError): + terminal_logger.info(entry) def stdout(msg): @@ -187,7 +199,7 @@ def subhelp(mapper): """ Look at every value of every key in the mapper and will output any ``class.help`` possible to return it as a string that will be sent to - stdout. + stderr. """ help_text_lines = [] for key, value in mapper.items(): diff --git a/ceph/src/ceph-volume/ceph_volume/tests/api/test_lvm.py b/ceph/src/ceph-volume/ceph_volume/tests/api/test_lvm.py index 3dc1ac6b9..4cedb4a56 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/api/test_lvm.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/api/test_lvm.py @@ -384,7 +384,7 @@ class TestVolumeGroupFree(object): vg = api.VolumeGroup(vg_name='nosize', vg_free='F') with pytest.raises(RuntimeError) as error: vg.free - assert "Unable to convert vg size to integer: 'F'" in str(error) + assert "Unable to convert vg size to integer: 'F'" in str(error.value) def test_invalid_float(self): vg = api.VolumeGroup(vg_name='nosize', vg_free=' g') @@ -464,7 +464,7 @@ class TestVolumeGroupSizing(object): def test_parts_and_size_errors(self): with pytest.raises(ValueError) as error: self.vg.sizing(parts=4, size=10) - assert "Cannot process sizing" in str(error) + assert "Cannot process sizing" in str(error.value) def test_zero_parts_produces_100_percent(self): result = self.vg.sizing(parts=0) diff --git a/ceph/src/ceph-volume/ceph_volume/tests/conftest.py b/ceph/src/ceph-volume/ceph_volume/tests/conftest.py index 8ec99bb84..fad7df44e 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/conftest.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/conftest.py @@ -1,5 +1,7 @@ import os import pytest +from ceph_volume.util import disk +from ceph_volume.util.constants import ceph_disk_guids from ceph_volume.api import lvm as lvm_api from ceph_volume import conf, configuration @@ -66,6 +68,7 @@ def fakedevice(factory): is_lvm_member=True, ) params.update(dict(kw)) + params['lvm_size'] = disk.Size(b=params['sys_api'].get("size", 0)) return factory(**params) return apply @@ -190,6 +193,67 @@ def tmpfile(tmpdir): return generate_file +@pytest.fixture +def disable_kernel_queries(monkeypatch): + ''' + This speeds up calls to Device and Disk + ''' + monkeypatch.setattr("ceph_volume.util.device.disk.get_devices", lambda: {}) + monkeypatch.setattr("ceph_volume.util.disk.udevadm_property", lambda *a, **kw: {}) + + +@pytest.fixture +def disable_lvm_queries(monkeypatch): + ''' + This speeds up calls to Device and Disk + ''' + monkeypatch.setattr("ceph_volume.util.device.lvm.get_lv_from_argument", lambda path: None) + monkeypatch.setattr("ceph_volume.util.device.lvm.get_lv", lambda vg_name, lv_uuid: None) + + +@pytest.fixture(params=[ + '', 'ceph data', 'ceph journal', 'ceph block', + 'ceph block.wal', 'ceph block.db', 'ceph lockbox']) +def ceph_partlabel(request): + return request.param + + +@pytest.fixture(params=list(ceph_disk_guids.keys())) +def ceph_parttype(request): + return request.param + + +@pytest.fixture +def lsblk_ceph_disk_member(monkeypatch, request, ceph_partlabel, ceph_parttype): + monkeypatch.setattr("ceph_volume.util.device.disk.lsblk", + lambda path: {'PARTLABEL': ceph_partlabel}) + # setting blkid here too in order to be able to fall back to PARTTYPE based + # membership + monkeypatch.setattr("ceph_volume.util.device.disk.blkid", + lambda path: {'PARTLABEL': '', + 'PARTTYPE': ceph_parttype}) + + +@pytest.fixture +def blkid_ceph_disk_member(monkeypatch, request, ceph_partlabel, ceph_parttype): + monkeypatch.setattr("ceph_volume.util.device.disk.blkid", + lambda path: {'PARTLABEL': ceph_partlabel, + 'PARTTYPE': ceph_parttype}) + + +@pytest.fixture(params=[ + ('gluster partition', 'gluster partition'), + # falls back to blkid + ('', 'gluster partition'), + ('gluster partition', ''), +]) +def device_info_not_ceph_disk_member(monkeypatch, request): + monkeypatch.setattr("ceph_volume.util.device.disk.lsblk", + lambda path: {'PARTLABEL': request.param[0]}) + monkeypatch.setattr("ceph_volume.util.device.disk.blkid", + lambda path: {'PARTLABEL': request.param[1]}) + + @pytest.fixture def device_info(monkeypatch): def apply(devices=None, lsblk=None, lv=None, blkid=None, udevadm=None): diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_bluestore.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_bluestore.py index 01a813c66..5782a5b31 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_bluestore.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_bluestore.py @@ -7,7 +7,7 @@ class TestSingleType(object): def test_hdd_device_is_large_enough(self, fakedevice, factory): args = factory(filtered_devices=[], osds_per_device=1, block_db_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) ] computed_osd = bluestore.SingleType(devices, args).computed['osds'][0] assert computed_osd['data']['percentage'] == 100 @@ -18,7 +18,7 @@ class TestSingleType(object): def test_sdd_device_is_large_enough(self, fakedevice, factory): args = factory(filtered_devices=[], osds_per_device=1, block_db_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=6073740000)) ] computed_osd = bluestore.SingleType(devices, args).computed['osds'][0] assert computed_osd['data']['percentage'] == 100 @@ -29,20 +29,20 @@ class TestSingleType(object): def test_device_cannot_have_many_osds_per_device(self, fakedevice, factory): args = factory(filtered_devices=[], osds_per_device=3, block_db_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) ] with pytest.raises(RuntimeError) as error: bluestore.SingleType(devices, args) - assert 'Unable to use device 5.66 GB /dev/sda' in str(error) + assert 'Unable to use device 5.66 GB /dev/sda' in str(error.value) def test_device_is_lvm_member_fails(self, fakedevice, factory): args = factory(filtered_devices=[], osds_per_device=1, block_db_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=True, sys_api=dict(rotational='1', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=True, rotational=True, sys_api=dict(size=6073740000)) ] with pytest.raises(RuntimeError) as error: bluestore.SingleType(devices, args) - assert 'Unable to use device, already a member of LVM' in str(error) + assert 'Unable to use device, already a member of LVM' in str(error.value) class TestMixedTypeConfiguredSize(object): @@ -53,8 +53,8 @@ class TestMixedTypeConfiguredSize(object): # 3GB block.db in ceph.conf conf_ceph(get_safe=lambda *a: 3147483640) args = factory(filtered_devices=[], osds_per_device=1, block_db_size=None) - ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=6073740000)) - hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=6073740000)) + hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) devices = [ssd, hdd] osd = bluestore.MixedType(devices, args).computed['osds'][0] @@ -69,27 +69,27 @@ class TestMixedTypeConfiguredSize(object): # 7GB block.db in ceph.conf conf_ceph(get_safe=lambda *a: 7747483640) args = factory(filtered_devices=[], osds_per_device=1, block_db_size=None) - ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=6073740000)) - hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=6073740000)) + hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) devices = [ssd, hdd] with pytest.raises(RuntimeError) as error: bluestore.MixedType(devices, args).computed['osds'][0] expected = 'Not enough space in fast devices (5.66 GB) to create 1 x 7.22 GB block.db LV' - assert expected in str(error) + assert expected in str(error.value) def test_multi_hdd_device_is_not_large_enough(self, stub_vgs, fakedevice, factory, conf_ceph): # 3GB block.db in ceph.conf conf_ceph(get_safe=lambda *a: 3147483640) args = factory(filtered_devices=[], osds_per_device=2, block_db_size=None) - ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=60737400000)) - hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=60737400000)) + hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) devices = [ssd, hdd] with pytest.raises(RuntimeError) as error: bluestore.MixedType(devices, args) expected = 'Unable to use device 5.66 GB /dev/sda, LVs would be smaller than 5GB' - assert expected in str(error) + assert expected in str(error.value) class TestMixedTypeLargeAsPossible(object): @@ -97,8 +97,8 @@ class TestMixedTypeLargeAsPossible(object): def test_hdd_device_is_large_enough(self, stub_vgs, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: None) args = factory(filtered_devices=[], osds_per_device=1, block_db_size=None) - ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=6073740000)) - hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=6073740000)) + hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) devices = [ssd, hdd] osd = bluestore.MixedType(devices, args).computed['osds'][0] @@ -113,8 +113,8 @@ class TestMixedTypeLargeAsPossible(object): def test_multi_hdd_device_is_large_enough(self, stub_vgs, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: None) args = factory(filtered_devices=[], osds_per_device=2, block_db_size=None) - ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=60073740000)) - hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=60073740000)) + ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=60073740000)) + hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=60073740000)) devices = [ssd, hdd] osd = bluestore.MixedType(devices, args).computed['osds'][0] @@ -129,11 +129,11 @@ class TestMixedTypeLargeAsPossible(object): def test_multi_hdd_device_is_not_large_enough(self, stub_vgs, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: None) args = factory(filtered_devices=[], osds_per_device=2, block_db_size=None) - ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=60737400000)) - hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + ssd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=60737400000)) + hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) devices = [ssd, hdd] with pytest.raises(RuntimeError) as error: bluestore.MixedType(devices, args) expected = 'Unable to use device 5.66 GB /dev/sda, LVs would be smaller than 5GB' - assert expected in str(error) + assert expected in str(error.value) diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_filestore.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_filestore.py index 0537e1e08..66f05b923 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_filestore.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_filestore.py @@ -9,7 +9,7 @@ class TestSingleType(object): conf_ceph(get_safe=lambda *a: '5120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=12073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=12073740000)) ] computed_osd = filestore.SingleType(devices, args).computed['osds'][0] assert computed_osd['data']['percentage'] == 55 @@ -21,18 +21,18 @@ class TestSingleType(object): conf_ceph(get_safe=lambda *a: '5120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) ] with pytest.raises(RuntimeError) as error: filestore.SingleType(devices, args) msg = "Unable to use device 5.66 GB /dev/sda, LVs would be smaller than 5GB" - assert msg in str(error) + assert msg in str(error.value) def test_ssd_device_is_large_enough(self, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: '5120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=12073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=12073740000)) ] computed_osd = filestore.SingleType(devices, args).computed['osds'][0] assert computed_osd['data']['percentage'] == 55 @@ -44,66 +44,66 @@ class TestSingleType(object): conf_ceph(get_safe=lambda *a: '5120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=6073740000)) ] with pytest.raises(RuntimeError) as error: filestore.SingleType(devices, args) msg = "Unable to use device 5.66 GB /dev/sda, LVs would be smaller than 5GB" - assert msg in str(error) + assert msg in str(error.value) def test_ssd_device_multi_osd(self, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: '5120') args = factory(filtered_devices=[], osds_per_device=4, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=16073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=16073740000)) ] with pytest.raises(RuntimeError) as error: filestore.SingleType(devices, args) msg = "Unable to use device 14.97 GB /dev/sda, LVs would be smaller than 5GB" - assert msg in str(error) + assert msg in str(error.value) def test_hdd_device_multi_osd(self, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: '5120') args = factory(filtered_devices=[], osds_per_device=4, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=16073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=16073740000)) ] with pytest.raises(RuntimeError) as error: filestore.SingleType(devices, args) msg = "Unable to use device 14.97 GB /dev/sda, LVs would be smaller than 5GB" - assert msg in str(error) + assert msg in str(error.value) def test_device_is_lvm_member_fails(self, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: '5120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=True, sys_api=dict(rotational='1', size=12073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=True, rotational=True, sys_api=dict(size=12073740000)) ] with pytest.raises(RuntimeError) as error: filestore.SingleType(devices, args) - assert 'Unable to use device, already a member of LVM' in str(error) + assert 'Unable to use device, already a member of LVM' in str(error.value) def test_hdd_device_with_small_configured_journal(self, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: '120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) ] with pytest.raises(RuntimeError) as error: filestore.SingleType(devices, args) msg = "journal sizes must be larger than 2GB, detected: 120.00 MB" - assert msg in str(error) + assert msg in str(error.value) def test_ssd_device_with_small_configured_journal(self, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: '120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=6073740000)) ] with pytest.raises(RuntimeError) as error: filestore.SingleType(devices, args) msg = "journal sizes must be larger than 2GB, detected: 120.00 MB" - assert msg in str(error) + assert msg in str(error.value) class TestMixedType(object): @@ -112,44 +112,44 @@ class TestMixedType(object): conf_ceph(get_safe=lambda *a: '120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=6073740000)), - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=6073740000)), + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) ] with pytest.raises(RuntimeError) as error: filestore.MixedType(devices, args) msg = "journal sizes must be larger than 2GB, detected: 120.00 MB" - assert msg in str(error) + assert msg in str(error.value) def test_ssd_device_is_not_large_enough(self, stub_vgs, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: '7120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=6073740000)), - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=6073740000)), + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) ] with pytest.raises(RuntimeError) as error: filestore.MixedType(devices, args) msg = "Not enough space in fast devices (5.66 GB) to create 1 x 6.95 GB journal LV" - assert msg in str(error) + assert msg in str(error.value) def test_hdd_device_is_lvm_member_fails(self, stub_vgs, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: '5120') args = factory(filtered_devices=[], osds_per_device=1, journal_size=None) devices = [ - fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='0', size=6073740000)), - fakedevice(used_by_ceph=False, is_lvm_member=True, sys_api=dict(rotational='1', size=6073740000)) + fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=False, sys_api=dict(size=6073740000)), + fakedevice(used_by_ceph=False, is_lvm_member=True, rotational=True, sys_api=dict(size=6073740000)) ] with pytest.raises(RuntimeError) as error: filestore.MixedType(devices, args) - assert 'Unable to use device, already a member of LVM' in str(error) + assert 'Unable to use device, already a member of LVM' in str(error.value) def test_ssd_is_lvm_member_doesnt_fail(self, volumes, stub_vgs, fakedevice, factory, conf_ceph): # fast PV, because ssd is an LVM member CephPV = lvm.PVolume(vg_name='fast', pv_name='/dev/sda', pv_tags='') ssd = fakedevice( - used_by_ceph=False, is_lvm_member=True, sys_api=dict(rotational='0', size=6073740000), pvs_api=[CephPV] + used_by_ceph=False, is_lvm_member=True, rotational=False, sys_api=dict(size=6073740000), pvs_api=[CephPV] ) - hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) # when get_api_vgs() gets called, it will return this one VG stub_vgs([ dict( @@ -171,12 +171,12 @@ class TestMixedType(object): CephPV1 = lvm.PVolume(vg_name='fast1', pv_name='/dev/sda', pv_tags='') CephPV2 = lvm.PVolume(vg_name='fast2', pv_name='/dev/sdb', pv_tags='') ssd1 = fakedevice( - used_by_ceph=False, is_lvm_member=True, sys_api=dict(rotational='0', size=6073740000), pvs_api=[CephPV1] + used_by_ceph=False, is_lvm_member=True, rotational=False, sys_api=dict(size=6073740000), pvs_api=[CephPV1] ) ssd2 = fakedevice( - used_by_ceph=False, is_lvm_member=True, sys_api=dict(rotational='0', size=6073740000), pvs_api=[CephPV2] + used_by_ceph=False, is_lvm_member=True, rotational=False, sys_api=dict(size=6073740000), pvs_api=[CephPV2] ) - hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, sys_api=dict(rotational='1', size=6073740000)) + hdd = fakedevice(used_by_ceph=False, is_lvm_member=False, rotational=True, sys_api=dict(size=6073740000)) # when get_api_vgs() gets called, it will return this one VG stub_vgs([ dict( @@ -195,16 +195,16 @@ class TestMixedType(object): with pytest.raises(RuntimeError) as error: filestore.MixedType(devices, args) - assert 'Could not find a common VG between devices' in str(error) + assert 'Could not find a common VG between devices' in str(error.value) def test_ssd_device_fails_multiple_osds(self, stub_vgs, fakedevice, factory, conf_ceph): conf_ceph(get_safe=lambda *a: '15120') args = factory(filtered_devices=[], osds_per_device=2, journal_size=None) devices = [ - fakedevice(is_lvm_member=False, sys_api=dict(rotational='0', size=16073740000)), - fakedevice(is_lvm_member=False, sys_api=dict(rotational='1', size=16073740000)) + fakedevice(is_lvm_member=False, rotational=False, sys_api=dict(size=16073740000)), + fakedevice(is_lvm_member=False, rotational=True, sys_api=dict(size=16073740000)) ] with pytest.raises(RuntimeError) as error: filestore.MixedType(devices, args) msg = "Not enough space in fast devices (14.97 GB) to create 2 x 14.77 GB journal LV" - assert msg in str(error) + assert msg in str(error.value) diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_validate.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_validate.py index 315ec7c5b..ebb93149b 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_validate.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/strategies/test_validate.py @@ -14,7 +14,7 @@ class TestMinimumDeviceSize(object): with pytest.raises(RuntimeError) as error: validators.minimum_device_size(devices) msg = "LVs would be smaller than 5GB" - assert msg in str(error) + assert msg in str(error.value) def test_large_device_multiple_osds_fails(self, fakedevice): devices = [fakedevice(sys_api=dict(size=6073740000))] @@ -23,7 +23,7 @@ class TestMinimumDeviceSize(object): devices, osds_per_device=4 ) msg = "LVs would be smaller than 5GB" - assert msg in str(error) + assert msg in str(error.value) class TestMinimumCollocatedDeviceSize(object): @@ -40,7 +40,7 @@ class TestMinimumCollocatedDeviceSize(object): with pytest.raises(RuntimeError) as error: validators.minimum_device_collocated_size(devices, self.journal_size) msg = "LVs would be smaller than 5GB" - assert msg in str(error) + assert msg in str(error.value) def test_large_device_multiple_osds_fails(self, fakedevice): devices = [fakedevice(sys_api=dict(size=16073740000))] @@ -49,4 +49,4 @@ class TestMinimumCollocatedDeviceSize(object): devices, self.journal_size, osds_per_device=3 ) msg = "LVs would be smaller than 5GB" - assert msg in str(error) + assert msg in str(error.value) diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py index 7520e52bf..cfa7de8e8 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py @@ -283,8 +283,8 @@ class TestActivateAll(object): activation = activate.Activate(args) activation.main() out, err = capsys.readouterr() - assert 'Was unable to find any OSDs to activate' in out - assert 'Verify OSDs are present with ' in out + assert 'Was unable to find any OSDs to activate' in err + assert 'Verify OSDs are present with ' in err def test_detects_running_osds(self, capsys, is_root, capture, monkeypatch): monkeypatch.setattr('ceph_volume.devices.lvm.activate.direct_report', lambda: direct_report) @@ -293,8 +293,8 @@ class TestActivateAll(object): activation = activate.Activate(args) activation.main() out, err = capsys.readouterr() - assert 'a8789a96ce8b process is active. Skipping activation' in out - assert 'b8218eaa1634 process is active. Skipping activation' in out + assert 'a8789a96ce8b process is active. Skipping activation' in err + assert 'b8218eaa1634 process is active. Skipping activation' in err def test_detects_osds_to_activate(self, is_root, capture, monkeypatch): monkeypatch.setattr('ceph_volume.devices.lvm.activate.direct_report', lambda: direct_report) diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_create.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_create.py index 62790c9eb..994038f3b 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_create.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_create.py @@ -21,9 +21,9 @@ class TestCreate(object): device_info() with pytest.raises(SystemExit): lvm.create.Create(argv=['--data', '/dev/sdfoo', '--filestore', '--bluestore']).main() - stdout, sterr = capsys.readouterr() + stdout, stderr = capsys.readouterr() expected = 'Cannot use --filestore (filestore) with --bluestore (bluestore)' - assert expected in stdout + assert expected in stderr def test_excludes_other_filestore_bluestore_flags(self, capsys, device_info): device_info() @@ -32,9 +32,9 @@ class TestCreate(object): '--bluestore', '--data', '/dev/sdfoo', '--journal', '/dev/sf14', ]).main() - stdout, sterr = capsys.readouterr() + stdout, stderr = capsys.readouterr() expected = 'Cannot use --bluestore (bluestore) with --journal (filestore)' - assert expected in stdout + assert expected in stderr def test_excludes_block_and_journal_flags(self, capsys, device_info): device_info() @@ -43,6 +43,6 @@ class TestCreate(object): '--bluestore', '--data', '/dev/sdfoo', '--block.db', 'vg/ceph1', '--journal', '/dev/sf14', ]).main() - stdout, sterr = capsys.readouterr() + stdout, stderr = capsys.readouterr() expected = 'Cannot use --block.db (bluestore) with --journal (filestore)' - assert expected in stdout + assert expected in stderr diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py index 173da9392..5c0fec756 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py @@ -79,6 +79,23 @@ class TestList(object): with pytest.raises(SystemExit): lvm.listing.List([]).list(args) + def test_lvs_list_is_created_just_once(self, monkeypatch, is_root, volumes, factory): + api.volumes_obj_create_count = 0 + + def monkey_populate(self): + api.volumes_obj_create_count += 1 + for lv_item in api.get_api_lvs(): + self.append(api.Volume(**lv_item)) + monkeypatch.setattr(api.Volumes, '_populate', monkey_populate) + + args = factory(format='pretty', device='/dev/sda1') + with pytest.raises(SystemExit): + lvm.listing.List([]).list(args) + + # XXX: Ideally, the count should be just 1. Volumes._populate() is + # being called thrice out of which only twice is moneky_populate. + assert api.volumes_obj_create_count == 2 + class TestFullReport(object): diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py index c7963bb2f..244da401b 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py @@ -28,8 +28,8 @@ class TestPrepareDevice(object): with pytest.raises(RuntimeError) as error: lvm.prepare.Prepare([]).prepare_device( '/dev/var/foo', 'data', 'asdf', '0') - assert 'Cannot use device (/dev/var/foo)' in str(error) - assert 'A vg/lv path or an existing device is needed' in str(error) + assert 'Cannot use device (/dev/var/foo)' in str(error.value) + assert 'A vg/lv path or an existing device is needed' in str(error.value) class TestGetClusterFsid(object): @@ -68,7 +68,7 @@ class TestPrepare(object): lvm.prepare.Prepare(argv=['--data', '/dev/sdfoo', '--filestore', '--bluestore']).main() stdout, stderr = capsys.readouterr() expected = 'Cannot use --filestore (filestore) with --bluestore (bluestore)' - assert expected in stdout + assert expected in stderr def test_excludes_other_filestore_bluestore_flags(self, capsys, device_info): device_info() @@ -79,7 +79,7 @@ class TestPrepare(object): ]).main() stdout, stderr = capsys.readouterr() expected = 'Cannot use --bluestore (bluestore) with --journal (filestore)' - assert expected in stdout + assert expected in stderr def test_excludes_block_and_journal_flags(self, capsys, device_info): device_info() @@ -90,7 +90,7 @@ class TestPrepare(object): ]).main() stdout, stderr = capsys.readouterr() expected = 'Cannot use --block.db (bluestore) with --journal (filestore)' - assert expected in stdout + assert expected in stderr def test_journal_is_required_with_filestore(self, is_root, monkeypatch, device_info): monkeypatch.setattr("os.path.exists", lambda path: True) @@ -98,7 +98,7 @@ class TestPrepare(object): with pytest.raises(SystemExit) as error: lvm.prepare.Prepare(argv=['--filestore', '--data', '/dev/sdfoo']).main() expected = '--journal is required when using --filestore' - assert expected in str(error) + assert expected in str(error.value) class TestGetJournalLV(object): diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py index 55daa4f87..20ca56b54 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py @@ -1,3 +1,4 @@ +import os import pytest from ceph_volume.api import lvm as api from ceph_volume.devices.lvm import zap @@ -90,6 +91,22 @@ class TestEnsureAssociatedLVs(object): result = zap.ensure_associated_lvs(volumes) assert result == ['/dev/VolGroup/block'] + def test_success_message_for_fsid(self, factory, is_root, capsys): + cli_zap = zap.Zap([]) + args = factory(devices=[], osd_id=None, osd_fsid='asdf-lkjh') + cli_zap.args = args + cli_zap.zap() + out, err = capsys.readouterr() + assert "Zapping successful for OSD: asdf-lkjh" in err + + def test_success_message_for_id(self, factory, is_root, capsys): + cli_zap = zap.Zap([]) + args = factory(devices=[], osd_id='1', osd_fsid=None) + cli_zap.args = args + cli_zap.zap() + out, err = capsys.readouterr() + assert "Zapping successful for OSD: 1" in err + def test_block_and_partition_are_found(self, volumes, monkeypatch): monkeypatch.setattr(zap.disk, 'get_device_from_partuuid', lambda x: '/dev/sdb1') tags = 'ceph.osd_id=0,ceph.osd_fsid=asdf-lkjh,ceph.journal_uuid=x,ceph.type=block' @@ -151,3 +168,26 @@ class TestEnsureAssociatedLVs(object): assert '/dev/VolGroup/lvjournal' in result assert '/dev/VolGroup/lvwal' in result assert '/dev/VolGroup/lvdb' in result + + +class TestWipeFs(object): + + def setup(self): + os.environ['CEPH_VOLUME_WIPEFS_INTERVAL'] = '0' + + def test_works_on_second_try(self, stub_call): + os.environ['CEPH_VOLUME_WIPEFS_TRIES'] = '2' + stub_call([('wiping /dev/sda', '', 1), ('', '', 0)]) + result = zap.wipefs('/dev/sda') + assert result is None + + def test_does_not_work_after_several_tries(self, stub_call): + os.environ['CEPH_VOLUME_WIPEFS_TRIES'] = '2' + stub_call([('wiping /dev/sda', '', 1), ('', '', 1)]) + with pytest.raises(RuntimeError): + zap.wipefs('/dev/sda') + + def test_does_not_work_default_tries(self, stub_call): + stub_call([('wiping /dev/sda', '', 1)]*8) + with pytest.raises(RuntimeError): + zap.wipefs('/dev/sda') diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/simple/test_activate.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/simple/test_activate.py index 885a6ec25..ac2dd0e7b 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/simple/test_activate.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/simple/test_activate.py @@ -15,7 +15,7 @@ class TestActivate(object): os.environ['CEPH_VOLUME_SIMPLE_JSON_DIR'] = '/non/existing/path' with pytest.raises(RuntimeError) as error: activate.Activate(['1', 'asdf']).main() - assert 'RuntimeError: Expected JSON config path not found' in str(error) + assert 'Expected JSON config path not found' in str(error.value) def test_main_spits_help_with_no_arguments(self, capsys): activate.Activate([]).main() @@ -51,10 +51,10 @@ class TestEnableSystemdUnits(object): activation.activate = lambda x: True activation.main() activation.enable_systemd_units('0', '1234') - out, err = capsys.readouterr() - assert 'Skipping enabling of `simple`' in out - assert 'Skipping masking of ceph-disk' in out - assert 'Skipping enabling and starting OSD simple' in out + stdout, stderr = capsys.readouterr() + assert 'Skipping enabling of `simple`' in stderr + assert 'Skipping masking of ceph-disk' in stderr + assert 'Skipping enabling and starting OSD simple' in stderr def test_no_systemd_flag_is_true(self, tmpfile, is_root): json_config = tmpfile(contents='{}') @@ -132,38 +132,48 @@ class TestValidateDevices(object): activation = activate.Activate([]) with pytest.raises(RuntimeError) as error: activation.validate_devices({'type': 'filestore', 'data': {}}) - assert 'Unable to activate filestore OSD due to missing devices' in str(error) + assert 'Unable to activate filestore OSD due to missing devices' in str(error.value) def test_filestore_missing_data(self): activation = activate.Activate([]) with pytest.raises(RuntimeError) as error: activation.validate_devices({'type': 'filestore', 'journal': {}}) - assert 'Unable to activate filestore OSD due to missing devices' in str(error) + assert 'Unable to activate filestore OSD due to missing devices' in str(error.value) def test_filestore_journal_device_found(self, capsys): activation = activate.Activate([]) with pytest.raises(RuntimeError): activation.validate_devices({'type': 'filestore', 'journal': {}}) stdout, stderr = capsys.readouterr() - assert "devices found: ['journal']" in stdout + assert "devices found: ['journal']" in stderr def test_filestore_data_device_found(self, capsys): activation = activate.Activate([]) with pytest.raises(RuntimeError): activation.validate_devices({'type': 'filestore', 'data': {}}) stdout, stderr = capsys.readouterr() - assert "devices found: ['data']" in stdout + assert "devices found: ['data']" in stderr def test_filestore_with_all_devices(self): activation = activate.Activate([]) result = activation.validate_devices({'type': 'filestore', 'journal': {}, 'data': {}}) assert result is True + def test_filestore_without_type(self): + activation = activate.Activate([]) + result = activation.validate_devices({'journal': {}, 'data': {}}) + assert result is True + def test_bluestore_with_all_devices(self): activation = activate.Activate([]) result = activation.validate_devices({'type': 'bluestore', 'data': {}, 'block': {}}) assert result is True + def test_bluestore_without_type(self): + activation = activate.Activate([]) + result = activation.validate_devices({'data': {}, 'block': {}}) + assert result is True + def test_bluestore_is_default(self): activation = activate.Activate([]) result = activation.validate_devices({'data': {}, 'block': {}}) @@ -174,17 +184,17 @@ class TestValidateDevices(object): with pytest.raises(RuntimeError): activation.validate_devices({'data': {}}) stdout, stderr = capsys.readouterr() - assert "devices found: ['data']" in stdout + assert "devices found: ['data']" in stderr def test_bluestore_missing_data(self): activation = activate.Activate([]) with pytest.raises(RuntimeError) as error: activation.validate_devices({'type': 'bluestore', 'block': {}}) - assert 'Unable to activate bluestore OSD due to missing devices' in str(error) + assert 'Unable to activate bluestore OSD due to missing devices' in str(error.value) def test_bluestore_block_device_found(self, capsys): activation = activate.Activate([]) with pytest.raises(RuntimeError): activation.validate_devices({'block': {}}) stdout, stderr = capsys.readouterr() - assert "devices found: ['block']" in stdout + assert "devices found: ['block']" in stderr diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/test_zap.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/test_zap.py index 6333e3a4e..42c4940f1 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/devices/test_zap.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/test_zap.py @@ -25,4 +25,4 @@ class TestZap(object): with pytest.raises(SystemExit): lvm.zap.Zap(argv=[device_name]).main() stdout, stderr = capsys.readouterr() - assert 'Refusing to zap' in stdout + assert 'Refusing to zap' in stderr diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/batch/playbooks/test.yml b/ceph/src/ceph-volume/ceph_volume/tests/functional/batch/playbooks/test.yml index c9375e2b7..1b0fe1f8c 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/functional/batch/playbooks/test.yml +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/batch/playbooks/test.yml @@ -46,7 +46,7 @@ msg: "lvm batch failed idempotency check" when: - batch_cmd.rc != 0 - - "'strategy changed' not in batch_cmd.stdout" + - "'strategy changed' not in batch_cmd.stderr" - name: run batch --report to see if devices get filtered command: "ceph-volume --cluster {{ cluster }} lvm batch --report --format=json --{{ osd_objectstore|default('bluestore') }} {{ '--dmcrypt' if dmcrypt|default(false) else '' }} {{ devices | join(' ') }}" @@ -59,5 +59,5 @@ fail: msg: "lvm batch --report failed idempotency check" when: - - batch_cmd.rc != 0 - - "'strategy changed' not in batch_cmd.stdout" + - report_cmd.rc != 0 + - "'strategy changed' not in report_cmd.stderr" diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/batch/tox.ini b/ceph/src/ceph-volume/ceph_volume/tests/functional/batch/tox.ini index db9652436..20553b8e0 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/functional/batch/tox.ini +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/batch/tox.ini @@ -17,6 +17,7 @@ setenv= ANSIBLE_SSH_RETRIES = 5 VAGRANT_CWD = {changedir} CEPH_VOLUME_DEBUG = 1 + DEBIAN_FRONTEND=noninteractive changedir= centos7-filestore-single_type: {toxinidir}/centos7/filestore/single-type centos7-filestore-single_type_dmcrypt: {toxinidir}/centos7/filestore/single-type-dmcrypt @@ -48,20 +49,23 @@ commands= # prepare nodes for testing with testinfra ansible-playbook -vv -i {changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/setup.yml - # test cluster state using testinfra - py.test -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {toxinidir}/../tests + # test cluster state using testinfra + py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # reboot all vms - attempt bash {toxinidir}/../scripts/vagrant_reload.sh {env:VAGRANT_UP_FLAGS:"--no-provision"} {posargs:--provider=virtualbox} + # after a reboot, osds may take about 20 seconds to come back up + sleep 30 + # retest to ensure cluster came back up correctly after rebooting - py.test -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # destroy an OSD, zap it's device and recreate it using it's ID ansible-playbook -vv -i {changedir}/hosts {changedir}/test.yml # retest to ensure cluster came back up correctly - py.test -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # test zap OSDs by ID ansible-playbook -vv -i {changedir}/hosts {changedir}/test_zap.yml diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/lvm/tox.ini b/ceph/src/ceph-volume/ceph_volume/tests/functional/lvm/tox.ini index d61c23719..b6b752ca8 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/functional/lvm/tox.ini +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/lvm/tox.ini @@ -18,6 +18,7 @@ setenv= ANSIBLE_SSH_RETRIES = 5 VAGRANT_CWD = {changedir} CEPH_VOLUME_DEBUG = 1 + DEBIAN_FRONTEND=noninteractive changedir= # plain/unencrypted centos7-filestore-create: {toxinidir}/centos7/filestore/create @@ -57,18 +58,21 @@ commands= ansible-playbook -vv -i {changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/setup.yml # test cluster state using testinfra - py.test -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # reboot all vms - attempt bash {toxinidir}/../scripts/vagrant_reload.sh {env:VAGRANT_UP_FLAGS:"--no-provision"} {posargs:--provider=virtualbox} + # after a reboot, osds may take about 20 seconds to come back up + sleep 30 + # retest to ensure cluster came back up correctly after rebooting - py.test -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # destroy an OSD, zap it's device and recreate it using it's ID ansible-playbook -vv -i {changedir}/hosts {changedir}/test.yml # retest to ensure cluster came back up correctly - py.test -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests vagrant destroy --force diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/playbooks/deploy.yml b/ceph/src/ceph-volume/ceph_volume/tests/functional/playbooks/deploy.yml index f46fcb1d4..6c2c50bba 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/functional/playbooks/deploy.yml +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/playbooks/deploy.yml @@ -16,6 +16,9 @@ vars: delegate_facts_host: True + environment: + DEBIAN_FRONTEND: noninteractive + pre_tasks: # If we can't get python2 installed before any module is used we will fail # so just try what we can to get it installed @@ -31,6 +34,17 @@ when: - systempython2.stat is undefined or systempython2.stat.exists == false + # Ansible will try to auto-install python-apt, in some systems this might be + # python3-apt, or python-apt, and it has caused whole runs to fail because + # it is trying to do an interactive prompt + - name: install python-apt and aptitude in debian based systems + raw: sudo apt-get -y install "{{ item }}" + ignore_errors: yes + with_items: + - python3-apt + - python-apt + - aptitude + - name: install python2 for fedora raw: sudo dnf -y install python creates=/usr/bin/python ignore_errors: yes @@ -63,6 +77,15 @@ - ansible_distribution == 'Fedora' - ansible_distribution_major_version|int >= 23 + - name: check if it is atomic host + stat: + path: /run/ostree-booted + register: stat_ostree + + - name: set_fact is_atomic + set_fact: + is_atomic: '{{ stat_ostree.stat.exists }}' + roles: - ceph-defaults - ceph-validate @@ -79,10 +102,12 @@ - ceph-facts - ceph-handler - ceph-common + tasks: + - name: rsync ceph-volume to test nodes on centos synchronize: - src: "{{ toxinidir}}/../../../../ceph_volume" + src: "{{ toxinidir }}/../../../../ceph_volume" dest: "/usr/lib/python2.7/site-packages" use_ssh_args: true when: @@ -91,7 +116,7 @@ - name: rsync ceph-volume to test nodes on ubuntu synchronize: - src: "{{ toxinidir}}/../../../../ceph_volume" + src: "{{ toxinidir }}/../../../../ceph_volume" dest: "/usr/lib/python2.7/dist-packages" use_ssh_args: true when: diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/scripts/output.py b/ceph/src/ceph-volume/ceph_volume/tests/functional/scripts/output.py new file mode 100644 index 000000000..160719444 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/scripts/output.py @@ -0,0 +1,5 @@ +import os +from ceph_volume import terminal + +char = os.environ.get('INVALID') +terminal.stdout(char) diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/scripts/test_unicode.sh b/ceph/src/ceph-volume/ceph_volume/tests/functional/scripts/test_unicode.sh new file mode 100644 index 000000000..e4ba4f0a6 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/scripts/test_unicode.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Not entirely sure why these executables don't seem to be available in the +# $PATH when running from tox. Calling out to `which` seems to fix it, at the +# expense of making the script a bit obtuse + +mktemp=$(which mktemp) +cat=$(which cat) +grep=$(which grep) +PYTHON_EXECUTABLE=`which python` +STDERR_FILE=$($mktemp) +INVALID="→" + +echo "stderr file created: $STDERR_FILE" + +INVALID="$INVALID" $PYTHON_EXECUTABLE $1 2> ${STDERR_FILE} + +retVal=$? + +if [ $retVal -ne 0 ]; then + echo "Failed test: Unexpected failure from running Python script" + echo "Below is output of stderr captured:" + $cat "${STDERR_FILE}" + exit $retVal +fi + +$grep --quiet "$INVALID" ${STDERR_FILE} + +retVal=$? +if [ $retVal -ne 0 ]; then + echo "Failed test: expected to find \"${INVALID}\" character in tmpfile: \"${STDERR_FILE}\"" + echo "Below is output of stderr captured:" + $cat "${STDERR_FILE}" +fi +exit $retVal diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/simple/tox.ini b/ceph/src/ceph-volume/ceph_volume/tests/functional/simple/tox.ini index 2856d9ad0..e493e13d2 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/functional/simple/tox.ini +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/simple/tox.ini @@ -18,6 +18,7 @@ setenv= ANSIBLE_SSH_RETRIES = 5 VAGRANT_CWD = {changedir} CEPH_VOLUME_DEBUG = 1 + DEBIAN_FRONTEND=noninteractive changedir= centos7-filestore-activate: {toxinidir}/centos7/filestore/activate centos7-bluestore-activate: {toxinidir}/centos7/bluestore/activate @@ -47,7 +48,7 @@ commands= ansible-playbook -vv -i {changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/setup.yml # test cluster state testinfra - py.test -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # make ceph-volume simple take over all the OSDs that got deployed, disabling ceph-disk ansible-playbook -vv -i {changedir}/hosts {changedir}/test.yml @@ -59,6 +60,6 @@ commands= sleep 120 # retest to ensure cluster came back up correctly after rebooting - py.test -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests vagrant destroy --force diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/tests/conftest.py b/ceph/src/ceph-volume/ceph_volume/tests/functional/tests/conftest.py index 05c9aa521..17cc996ed 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/functional/tests/conftest.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/tests/conftest.py @@ -19,7 +19,7 @@ def node(host, request): ceph_dev_branch = os.environ.get("CEPH_DEV_BRANCH", "master") group_names = ansible_vars["group_names"] num_osd_ports = 4 - if ceph_dev_branch in ['luminous', 'mimic']: + if 'mimic' in ceph_dev_branch or 'luminous' in ceph_dev_branch: num_osd_ports = 2 # capture the initial/default state diff --git a/ceph/src/ceph-volume/ceph_volume/tests/test_configuration.py b/ceph/src/ceph-volume/ceph_volume/tests/test_configuration.py index 0009532c4..9af6cd9be 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/test_configuration.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/test_configuration.py @@ -28,13 +28,13 @@ class TestConf(object): def test_get_non_existing_list(self): cfg = configuration.Conf() cfg.is_valid = lambda: True - cfg.readfp(self.conf_file) + cfg.read_conf(self.conf_file) assert cfg.get_list('global', 'key') == [] def test_get_non_existing_list_get_default(self): cfg = configuration.Conf() cfg.is_valid = lambda: True - cfg.readfp(self.conf_file) + cfg.read_conf(self.conf_file) assert cfg.get_list('global', 'key', ['a']) == ['a'] def test_get_rid_of_comments(self): @@ -45,7 +45,7 @@ class TestConf(object): default = 0 # this is a comment """)) - cfg.readfp(conf_file) + cfg.read_conf(conf_file) assert cfg.get_list('foo', 'default') == ['0'] def test_gets_split_on_commas(self): @@ -56,7 +56,7 @@ class TestConf(object): default = 0,1,2,3 # this is a comment """)) - cfg.readfp(conf_file) + cfg.read_conf(conf_file) assert cfg.get_list('foo', 'default') == ['0', '1', '2', '3'] def test_spaces_and_tabs_are_ignored(self): @@ -67,7 +67,7 @@ class TestConf(object): default = 0, 1, 2 ,3 # this is a comment """)) - cfg.readfp(conf_file) + cfg.read_conf(conf_file) assert cfg.get_list('foo', 'default') == ['0', '1', '2', '3'] @@ -106,7 +106,7 @@ class TestLoad(object): with pytest.raises(RuntimeError): configuration.load(ceph_conf) stdout, stderr = capsys.readouterr() - assert 'File contains no section headers' in stdout + assert 'File contains no section headers' in stderr @pytest.mark.parametrize('commented', ['colon','hash']) def test_coment_as_a_value(self, tmpdir, commented): diff --git a/ceph/src/ceph-volume/ceph_volume/tests/test_main.py b/ceph/src/ceph-volume/ceph_volume/tests/test_main.py index 45dcfff85..b88b2bc50 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/test_main.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/test_main.py @@ -37,7 +37,7 @@ class TestVolume(object): main.Volume(argv=['ceph-volume', '--cluster', 'barnacle', 'lvm', '--help']) # make sure we aren't causing an actual error assert error.value.code == 0 - log = caplog.records[1] + log = caplog.records[-1] assert log.message == 'ignoring inability to load ceph.conf' assert log.levelname == 'ERROR' @@ -46,6 +46,6 @@ class TestVolume(object): main.Volume(argv=['ceph-volume', '--cluster', 'barnacle', 'lvm', '--help']) # make sure we aren't causing an actual error assert error.value.code == 0 - log = caplog.records[0] + log = caplog.records[-2] assert log.message == 'Running command: ceph-volume --cluster barnacle lvm --help' assert log.levelname == 'INFO' diff --git a/ceph/src/ceph-volume/ceph_volume/tests/test_process.py b/ceph/src/ceph-volume/ceph_volume/tests/test_process.py index c9dfaeebf..46e5c40e6 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/test_process.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/test_process.py @@ -1,4 +1,5 @@ import pytest +import logging from ceph_volume.tests.conftest import Factory from ceph_volume import process @@ -28,6 +29,7 @@ def mock_call(monkeypatch): class TestCall(object): def test_stderr_terminal_and_logfile(self, mock_call, caplog, capsys): + caplog.set_level(logging.INFO) mock_call(stdout='stdout\n', stderr='some stderr message\n') process.call(['ls'], terminal_verbose=True) out, err = capsys.readouterr() @@ -35,9 +37,10 @@ class TestCall(object): assert 'Running command: ' in log_lines[0] assert 'ls' in log_lines[0] assert 'stderr some stderr message' in log_lines[-1] - assert 'some stderr message' in out + assert 'some stderr message' in err def test_stderr_terminal_and_logfile_off(self, mock_call, caplog, capsys): + caplog.set_level(logging.INFO) mock_call(stdout='stdout\n', stderr='some stderr message\n') process.call(['ls'], terminal_verbose=False) out, err = capsys.readouterr() @@ -48,6 +51,7 @@ class TestCall(object): assert out == '' def test_verbose_on_failure(self, mock_call, caplog, capsys): + caplog.set_level(logging.INFO) mock_call(stdout='stdout\n', stderr='stderr\n', returncode=1) process.call(['ls'], terminal_verbose=False, logfile_verbose=False) out, err = capsys.readouterr() @@ -55,9 +59,11 @@ class TestCall(object): assert 'Running command: ' in log_lines assert 'ls' in log_lines assert 'stderr' in log_lines - assert 'stdout: stdout' in out + assert 'stdout: stdout' in err + assert out == '' def test_silent_verbose_on_failure(self, mock_call, caplog, capsys): + caplog.set_level(logging.INFO) mock_call(stdout='stdout\n', stderr='stderr\n', returncode=1) process.call(['ls'], verbose_on_failure=False) out, err = capsys.readouterr() diff --git a/ceph/src/ceph-volume/ceph_volume/tests/test_terminal.py b/ceph/src/ceph-volume/ceph_volume/tests/test_terminal.py index 9435dbb26..fdf219070 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/test_terminal.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/test_terminal.py @@ -1,5 +1,15 @@ +# -*- mode:python; tab-width:4; indent-tabs-mode:nil; coding:utf-8 -*- + +import codecs +import io +try: + from io import StringIO +except ImportError: + from StringIO import StringIO import pytest +import sys from ceph_volume import terminal +from ceph_volume.log import setup_console class SubCommand(object): @@ -66,3 +76,68 @@ class TestDispatch(object): with pytest.raises(SystemExit) as error: terminal.dispatch({'sub': BadSubCommand}, argv=['sub']) assert str(error.value) == '100' + + +@pytest.fixture +def stream(): + def make_stream(buffer, encoding): + # mock a stdout with given encoding + if sys.version_info >= (3, 0): + stderr = sys.stderr + stream = io.TextIOWrapper(buffer, + encoding=encoding, + errors=stderr.errors, + newline=stderr.newlines, + line_buffering=stderr.line_buffering) + else: + stream = codecs.getwriter(encoding)(buffer) + # StreamWriter does not have encoding attached to it, it will ask + # the inner buffer for "encoding" attribute in this case + stream.encoding = encoding + return stream + return make_stream + + +class TestWriteUnicode(object): + + def setup(self): + self.octpus_and_squid_en = u'octpus and squid' + self.octpus_and_squid_zh = u'章鱼和鱿鱼' + self.message = self.octpus_and_squid_en + self.octpus_and_squid_zh + setup_console() + + def test_stdout_writer(self, capsys): + # should work with whatever stdout is + terminal.stdout(self.message) + _, err = capsys.readouterr() + assert self.octpus_and_squid_en in err + assert self.octpus_and_squid_zh in err + + @pytest.mark.parametrize('encoding', ['ascii', 'utf8']) + def test_writer_log(self, stream, encoding, monkeypatch, caplog): + writer = StringIO() + terminal._Write(_writer=writer).raw(self.message) + writer.flush() + writer.seek(0) + output = writer.readlines()[0] + assert self.octpus_and_squid_en in output + + @pytest.mark.parametrize('encoding', ['utf8']) + def test_writer(self, encoding, stream, monkeypatch, capsys, caplog): + buffer = io.BytesIO() + writer = stream(buffer, encoding) + terminal._Write(_writer=writer).raw(self.message) + writer.flush() + writer.seek(0) + val = buffer.getvalue() + assert self.octpus_and_squid_en.encode(encoding) in val + + def test_writer_uses_log_on_unicodeerror(self, stream, monkeypatch, capture): + + if sys.version_info > (3,): + pytest.skip("Something breaks inside of pytest's capsys") + monkeypatch.setattr(terminal.terminal_logger, 'info', capture) + buffer = io.BytesIO() + writer = stream(buffer, 'ascii') + terminal._Write(_writer=writer).raw(self.message) + assert self.octpus_and_squid_en in capture.calls[0]['args'][0] diff --git a/ceph/src/ceph-volume/ceph_volume/tests/util/test_arg_validators.py b/ceph/src/ceph-volume/ceph_volume/tests/util/test_arg_validators.py index 2167aeac1..844518a44 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/util/test_arg_validators.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/util/test_arg_validators.py @@ -25,7 +25,7 @@ class TestOSDPath(object): validator = arg_validators.OSDPath() with pytest.raises(argparse.ArgumentError) as error: validator(tmppath) - assert 'Required file (ceph_fsid) was not found in OSD' in str(error) + assert 'Required file (ceph_fsid) was not found in OSD' in str(error.value) class TestExcludeGroupOptions(object): @@ -70,7 +70,7 @@ class TestExcludeGroupOptions(object): self.parser, ['filestore', 'bluestore'], argv=argv ) stdout, stderr = capsys.readouterr() - assert 'Cannot use --filestore (filestore) with --bluestore (bluestore)' in stdout + assert 'Cannot use --filestore (filestore) with --bluestore (bluestore)' in stderr class TestValidDevice(object): diff --git a/ceph/src/ceph-volume/ceph_volume/tests/util/test_device.py b/ceph/src/ceph-volume/ceph_volume/tests/util/test_device.py index 00cb5a885..ecdceaaa2 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/util/test_device.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/util/test_device.py @@ -122,39 +122,46 @@ class TestDevice(object): disk = device.Device("/dev/sda") assert not disk.is_mapper - def test_is_ceph_disk_member_lsblk(self, device_info): - lsblk = {"PARTLABEL": "ceph data"} - device_info(lsblk=lsblk) + @pytest.mark.usefixtures("lsblk_ceph_disk_member", + "disable_kernel_queries", + "disable_lvm_queries") + def test_is_ceph_disk_lsblk(self, monkeypatch): disk = device.Device("/dev/sda") assert disk.is_ceph_disk_member - def test_is_ceph_disk_member_not_available(self, device_info): - lsblk = {"PARTLABEL": "ceph data"} - device_info(lsblk=lsblk) + @pytest.mark.usefixtures("blkid_ceph_disk_member", + "disable_kernel_queries", + "disable_lvm_queries") + def test_is_ceph_disk_blkid(self, monkeypatch): + monkeypatch.setattr("ceph_volume.util.device.disk.lsblk", + lambda path: {'PARTLABEL': ""}) + disk = device.Device("/dev/sda") + assert disk.is_ceph_disk_member + + @pytest.mark.usefixtures("lsblk_ceph_disk_member", + "disable_kernel_queries", + "disable_lvm_queries") + def test_is_ceph_disk_member_not_available_lsblk(self, monkeypatch): disk = device.Device("/dev/sda") assert disk.is_ceph_disk_member assert not disk.available assert "Used by ceph-disk" in disk.rejected_reasons - def test_is_not_ceph_disk_member_lsblk(self, device_info): - lsblk = {"PARTLABEL": "gluster partition"} - device_info(lsblk=lsblk) - disk = device.Device("/dev/sda") - assert disk.is_ceph_disk_member is False - - def test_is_ceph_disk_member_blkid(self, device_info): - # falls back to blkid - lsblk = {"PARTLABEL": ""} - blkid = {"PARTLABEL": "ceph data"} - device_info(lsblk=lsblk, blkid=blkid) + @pytest.mark.usefixtures("blkid_ceph_disk_member", + "disable_kernel_queries", + "disable_lvm_queries") + def test_is_ceph_disk_member_not_available_blkid(self, monkeypatch): + monkeypatch.setattr("ceph_volume.util.device.disk.lsblk", + lambda path: {'PARTLABEL': ""}) disk = device.Device("/dev/sda") assert disk.is_ceph_disk_member + assert not disk.available + assert "Used by ceph-disk" in disk.rejected_reasons - def test_is_not_ceph_disk_member_blkid(self, device_info): - # falls back to blkid - lsblk = {"PARTLABEL": ""} - blkid = {"PARTLABEL": "gluster partition"} - device_info(lsblk=lsblk, blkid=blkid) + @pytest.mark.usefixtures("device_info_not_ceph_disk_member", + "disable_lvm_queries", + "disable_kernel_queries") + def test_is_not_ceph_disk_member_lsblk(self): disk = device.Device("/dev/sda") assert disk.is_ceph_disk_member is False @@ -346,12 +353,6 @@ class TestDeviceOrdering(object): assert sdd > sdb -ceph_partlabels = [ - 'ceph data', 'ceph journal', 'ceph block', - 'ceph block.wal', 'ceph block.db', 'ceph lockbox' -] - - class TestCephDiskDevice(object): def test_partlabel_lsblk(self, device_info): @@ -369,11 +370,12 @@ class TestCephDiskDevice(object): assert disk.partlabel == 'ceph data' - @pytest.mark.parametrize("label", ceph_partlabels) - def test_is_member_blkid(self, device_info, label): - lsblk = {"PARTLABEL": ""} - blkid = {"PARTLABEL": label} - device_info(lsblk=lsblk, blkid=blkid) + @pytest.mark.usefixtures("blkid_ceph_disk_member", + "disable_kernel_queries", + "disable_lvm_queries") + def test_is_member_blkid(self, monkeypatch): + monkeypatch.setattr("ceph_volume.util.device.disk.lsblk", + lambda path: {'PARTLABEL': ""}) disk = device.CephDiskDevice(device.Device("/dev/sda")) assert disk.is_member is True @@ -402,10 +404,10 @@ class TestCephDiskDevice(object): disk = device.Device("/dev/sda") assert disk.available - @pytest.mark.parametrize("label", ceph_partlabels) - def test_is_member_lsblk(self, device_info, label): - lsblk = {"PARTLABEL": label} - device_info(lsblk=lsblk) + @pytest.mark.usefixtures("lsblk_ceph_disk_member", + "disable_kernel_queries", + "disable_lvm_queries") + def test_is_member_lsblk(self): disk = device.CephDiskDevice(device.Device("/dev/sda")) assert disk.is_member is True @@ -417,22 +419,23 @@ class TestCephDiskDevice(object): assert disk.type == 'unknown' - @pytest.mark.parametrize("label", ceph_partlabels) - def test_type_blkid(self, device_info, label): - expected = label.split()[-1].split('.')[-1] - lsblk = {"PARTLABEL": ""} - blkid = {"PARTLABEL": label} - device_info(lsblk=lsblk, blkid=blkid) + ceph_types = ['data', 'wal', 'db', 'lockbox', 'journal', 'block'] + + @pytest.mark.usefixtures("blkid_ceph_disk_member", + "disable_kernel_queries", + "disable_lvm_queries") + def test_type_blkid(self, monkeypatch, device_info, ceph_partlabel): + monkeypatch.setattr("ceph_volume.util.device.disk.lsblk", + lambda path: {'PARTLABEL': ''}) disk = device.CephDiskDevice(device.Device("/dev/sda")) - assert disk.type == expected + assert disk.type in self.ceph_types - @pytest.mark.parametrize("label", ceph_partlabels) - def test_type_lsblk(self, device_info, label): - expected = label.split()[-1].split('.')[-1] - lsblk = {"PARTLABEL": label} - blkid = {"PARTLABEL": ''} - device_info(lsblk=lsblk, blkid=blkid) + @pytest.mark.usefixtures("blkid_ceph_disk_member", + "lsblk_ceph_disk_member", + "disable_kernel_queries", + "disable_lvm_queries") + def test_type_lsblk(self, device_info, ceph_partlabel): disk = device.CephDiskDevice(device.Device("/dev/sda")) - assert disk.type == expected + assert disk.type in self.ceph_types diff --git a/ceph/src/ceph-volume/ceph_volume/tests/util/test_prepare.py b/ceph/src/ceph-volume/ceph_volume/tests/util/test_prepare.py index c611480ca..2ad1c4b8f 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/util/test_prepare.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/util/test_prepare.py @@ -319,7 +319,7 @@ class TestMkfsBluestore(object): stub_call(([], [], 1)) with pytest.raises(RuntimeError) as error: prepare.osd_mkfs_bluestore('1', 'asdf-1234', keyring='keyring') - assert "Command failed with exit code 1" in str(error) + assert "Command failed with exit code 1" in str(error.value) def test_non_zero_exit_formats_command_correctly(self, stub_call, monkeypatch): conf.cluster = 'ceph' @@ -336,7 +336,7 @@ class TestMkfsBluestore(object): '--keyfile', '-', '--osd-data', '/var/lib/ceph/osd/ceph-1/', '--osd-uuid', 'asdf-1234', '--setuser', 'ceph', '--setgroup', 'ceph']) - assert expected in str(error) + assert expected in str(error.value) class TestGetJournalSize(object): @@ -389,5 +389,5 @@ class TestGetJournalSize(object): """)) with pytest.raises(RuntimeError) as error: prepare.get_journal_size() - assert 'journal sizes must be larger' in str(error) - assert 'detected: 1024.00 MB' in str(error) + assert 'journal sizes must be larger' in str(error.value) + assert 'detected: 1024.00 MB' in str(error.value) diff --git a/ceph/src/ceph-volume/ceph_volume/tests/util/test_system.py b/ceph/src/ceph-volume/ceph_volume/tests/util/test_system.py index bf71e8746..d0919c998 100644 --- a/ceph/src/ceph-volume/ceph_volume/tests/util/test_system.py +++ b/ceph/src/ceph-volume/ceph_volume/tests/util/test_system.py @@ -213,6 +213,6 @@ class TestWhich(object): monkeypatch.setattr(system.os.path, 'isfile', lambda x: True) monkeypatch.setattr(system.os.path, 'exists', lambda x: False) system.which('exedir') - stdout, stderr = capsys.readouterr() - assert 'Absolute path not found for executable: exedir' in stdout - assert 'Ensure $PATH environment variable contains common executable locations' in stdout + cap = capsys.readouterr() + assert 'Absolute path not found for executable: exedir' in cap.err + assert 'Ensure $PATH environment variable contains common executable locations' in cap.err diff --git a/ceph/src/ceph-volume/ceph_volume/util/constants.py b/ceph/src/ceph-volume/ceph_volume/util/constants.py index ac2832482..3ec819ec3 100644 --- a/ceph/src/ceph-volume/ceph_volume/util/constants.py +++ b/ceph/src/ceph-volume/ceph_volume/util/constants.py @@ -23,11 +23,24 @@ ceph_disk_guids = { 'cafecafe-9b03-4f30-b4c6-35865ceff106': {'type': 'block', 'encrypted': True, 'encryption_type': 'luks'}, '166418da-c469-4022-adf4-b30afd37f176': {'type': 'block.db', 'encrypted': True, 'encryption_type': 'luks'}, '86a32090-3647-40b9-bbbd-38d8c573aa86': {'type': 'block.wal', 'encrypted': True, 'encryption_type': 'luks'}, - '4fbd7e29-9d25-41b8-afd0-35865ceff05d': {'type': 'osd', 'encrypted': True, 'encryption_type': 'luks'}, + '4fbd7e29-9d25-41b8-afd0-35865ceff05d': {'type': 'data', 'encrypted': True, 'encryption_type': 'luks'}, # plain '45b0969e-9b03-4f30-b4c6-5ec00ceff106': {'type': 'journal', 'encrypted': True, 'encryption_type': 'plain'}, 'cafecafe-9b03-4f30-b4c6-5ec00ceff106': {'type': 'block', 'encrypted': True, 'encryption_type': 'plain'}, '93b0052d-02d9-4d8a-a43b-33a3ee4dfbc3': {'type': 'block.db', 'encrypted': True, 'encryption_type': 'plain'}, '306e8683-4fe2-4330-b7c0-00a917c16966': {'type': 'block.wal', 'encrypted': True, 'encryption_type': 'plain'}, - '4fbd7e29-9d25-41b8-afd0-5ec00ceff05d': {'type': 'osd', 'encrypted': True, 'encryption_type': 'plain'}, + '4fbd7e29-9d25-41b8-afd0-5ec00ceff05d': {'type': 'data', 'encrypted': True, 'encryption_type': 'plain'}, + # regular guids that differ from plain + 'fb3aabf9-d25f-47cc-bf5e-721d1816496b': {'type': 'lockbox', 'encrypted': False, 'encryption_type': None}, + '30cd0809-c2b2-499c-8879-2d6b78529876': {'type': 'block.db', 'encrypted': False, 'encryption_type': None}, + '5ce17fce-4087-4169-b7ff-056cc58473f9': {'type': 'block.wal', 'encrypted': False, 'encryption_type': None}, + '4fbd7e29-9d25-41b8-afd0-062c0ceff05d': {'type': 'data', 'encrypted': False, 'encryption_type': None}, + 'cafecafe-9b03-4f30-b4c6-b4b80ceff106': {'type': 'block', 'encrypted': False, 'encryption_type': None}, + # multipath + '01b41e1b-002a-453c-9f17-88793989ff8f': {'type': 'block.wal', 'encrypted': False, 'encryption_type': None}, + 'ec6d6385-e346-45dc-be91-da2a7c8b3261': {'type': 'block.wal', 'encrypted': False, 'encryption_type': None}, + '45b0969e-8ae0-4982-bf9d-5a8d867af560': {'type': 'journal', 'encrypted': False, 'encryption_type': None}, + '4fbd7e29-8ae0-4982-bf9d-5a8d867af560': {'type': 'data', 'encrypted': False, 'encryption_type': None}, + '7f4a666a-16f3-47a2-8445-152ef4d03f6c': {'type': 'lockbox', 'encrypted': False, 'encryption_type': None}, + 'cafecafe-8ae0-4982-bf9d-5a8d867af560': {'type': 'block', 'encrypted': False, 'encryption_type': None}, } diff --git a/ceph/src/ceph-volume/ceph_volume/util/device.py b/ceph/src/ceph-volume/ceph_volume/util/device.py index 29a01effa..50b74ca0f 100644 --- a/ceph/src/ceph-volume/ceph_volume/util/device.py +++ b/ceph/src/ceph-volume/ceph_volume/util/device.py @@ -5,6 +5,7 @@ from functools import total_ordering from ceph_volume import sys_info from ceph_volume.api import lvm from ceph_volume.util import disk +from ceph_volume.util.constants import ceph_disk_guids report_template = """ {dev:<25} {size:<12} {rot!s:<7} {available!s:<9} {model}""" @@ -401,12 +402,24 @@ class CephDiskDevice(object): return lsblk_partlabel return self.device.blkid_api.get('PARTLABEL', '') + @property + def parttype(self): + """ + Seems like older version do not detect PARTTYPE correctly (assuming the + info in util/disk.py#lsblk is still valid). + SImply resolve to using blkid since lsblk will throw an error if asked + for an unknown columns + """ + return self.device.blkid_api.get('PARTTYPE', '') + @property def is_member(self): if self._is_ceph_disk_member is None: if 'ceph' in self.partlabel: self._is_ceph_disk_member = True return True + elif self.parttype in ceph_disk_guids.keys(): + return True return False return self._is_ceph_disk_member @@ -421,4 +434,5 @@ class CephDiskDevice(object): for t in types: if t in self.partlabel: return t - return 'unknown' + label = ceph_disk_guids.get(self.parttype, {}) + return label.get('type', 'unknown').split('.')[-1] diff --git a/ceph/src/ceph-volume/ceph_volume/util/disk.py b/ceph/src/ceph-volume/ceph_volume/util/disk.py index da6411329..49ccdb899 100644 --- a/ceph/src/ceph-volume/ceph_volume/util/disk.py +++ b/ceph/src/ceph-volume/ceph_volume/util/disk.py @@ -51,6 +51,7 @@ def _blkid_parser(output): 'TYPE': 'TYPE', 'PART_ENTRY_NAME': 'PARTLABEL', 'PART_ENTRY_UUID': 'PARTUUID', + 'PART_ENTRY_TYPE': 'PARTTYPE', 'PTTYPE': 'PTTYPE', } diff --git a/ceph/src/ceph-volume/ceph_volume/util/encryption.py b/ceph/src/ceph-volume/ceph_volume/util/encryption.py index e2b3ca164..df7eb69d8 100644 --- a/ceph/src/ceph-volume/ceph_volume/util/encryption.py +++ b/ceph/src/ceph-volume/ceph_volume/util/encryption.py @@ -103,7 +103,8 @@ def dmcrypt_close(mapping): logger.debug('device mapper path does not exist %s' % mapping) logger.debug('will skip cryptsetup removal') return - process.run(['cryptsetup', 'remove', mapping]) + # don't be strict about the remove call, but still warn on the terminal if it fails + process.run(['cryptsetup', 'remove', mapping], stop_on_error=False) def get_dmcrypt_key(osd_id, osd_fsid, lockbox_keyring=None): diff --git a/ceph/src/ceph-volume/ceph_volume/util/system.py b/ceph/src/ceph-volume/ceph_volume/util/system.py index b637f023a..98f6fc42d 100644 --- a/ceph/src/ceph-volume/ceph_volume/util/system.py +++ b/ceph/src/ceph-volume/ceph_volume/util/system.py @@ -214,9 +214,9 @@ def device_is_mounted(dev, destination=None): ) return True else: - logger.info('%s was found as mounted') + logger.info('%s was found as mounted', dev) return True - logger.info('%s was not found as mounted') + logger.info('%s was not found as mounted', dev) return False diff --git a/ceph/src/ceph-volume/shell_tox.ini b/ceph/src/ceph-volume/shell_tox.ini new file mode 100644 index 000000000..5cd4606e4 --- /dev/null +++ b/ceph/src/ceph-volume/shell_tox.ini @@ -0,0 +1,11 @@ +[tox] +envlist = py27, py35, py36 +skip_missing_interpreters = true + +[testenv] +passenv=* +whitelist_externals= + bash + grep + mktemp +commands=bash {posargs:ceph_volume/tests/functional/scripts/test_unicode.sh} {posargs:ceph_volume/tests/functional/scripts/output.py} diff --git a/ceph/src/ceph-volume/tox.ini b/ceph/src/ceph-volume/tox.ini index fce465def..7cd9059f6 100644 --- a/ceph/src/ceph-volume/tox.ini +++ b/ceph/src/ceph-volume/tox.ini @@ -1,5 +1,6 @@ [tox] envlist = py27, py35, py36, flake8 +skip_missing_interpreters = true [testenv] deps= diff --git a/ceph/src/ceph_osd.cc b/ceph/src/ceph_osd.cc index efab291e6..0fcd8681b 100644 --- a/ceph/src/ceph_osd.cc +++ b/ceph/src/ceph_osd.cc @@ -27,6 +27,7 @@ using namespace std; #include "include/ceph_features.h" #include "common/config.h" +#include "common/version.h" #include "mon/MonMap.h" @@ -403,8 +404,10 @@ flushjournal_out: string magic; uuid_d cluster_fsid, osd_fsid; + int require_osd_release = 0; int w; - int r = OSD::peek_meta(store, magic, cluster_fsid, osd_fsid, w); + int r = OSD::peek_meta(store, &magic, &cluster_fsid, &osd_fsid, &w, + &require_osd_release); if (r < 0) { derr << TEXT_RED << " ** ERROR: unable to open OSD superblock on " << g_conf->osd_data << ": " << cpp_strerror(-r) @@ -434,6 +437,14 @@ flushjournal_out: exit(0); } + if (require_osd_release > 0 && + require_osd_release + 2 < ceph_release()) { + derr << "OSD's recorded require_osd_release " << require_osd_release + << " + 2 < this release " << ceph_release() + << "; you can only upgrade 2 releases at a time" << dendl; + exit(1); + } + pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC |CEPH_PICK_ADDRESS_CLUSTER); diff --git a/ceph/src/civetweb/.travis.yml b/ceph/src/civetweb/.travis.yml index 80079af75..2dd926cff 100644 --- a/ceph/src/civetweb/.travis.yml +++ b/ceph/src/civetweb/.travis.yml @@ -1,2485 +1,694 @@ -language: c - -sudo: false - -compiler: - - gcc - - clang - -os: - - linux - - osx - -env: - global: - - BUILD_TYPE=Coverage - - ENABLE_SSL_DYNAMIC_LOADING=YES - - ENABLE_CXX=NO - - ENABLE_LUA=NO - - ENABLE_LUA_SHARED=NO - - C_STANDARD=auto - - CXX_STANDARD=auto - matrix: - # Build all combinations of feature options - # TODO: Lua is still missing - - FEATURES=0 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=0 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=1 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=1 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=2 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=2 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=3 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=3 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=4 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=4 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=5 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=5 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=6 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=6 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=7 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=7 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=8 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=8 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=9 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=9 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=10 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=10 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=11 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=11 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=12 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=12 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=13 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=13 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=14 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=14 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=15 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=15 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=NO - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=16 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=16 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=17 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=17 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=18 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=18 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=19 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=19 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=20 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=20 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=21 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=21 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=22 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=22 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=23 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=23 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=NO - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=24 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=24 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=25 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=25 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=26 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=26 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=27 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=27 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=YES - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=28 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=28 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=29 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=29 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=NO - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=30 - BUILD_SHARED=NO - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=30 - BUILD_SHARED=YES - NO_FILES=YES - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=31 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=31 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=NO - - FEATURES=31 - BUILD_SHARED=NO - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=YES - - FEATURES=31 - BUILD_SHARED=YES - NO_FILES=NO - ENABLE_SSL=YES - NO_CGI=NO - ENABLE_IPV6=YES - ENABLE_WEBSOCKETS=YES - ENABLE_LUA=NO - ENABLE_DUKTAPE=NO - NO_CACHING=YES -# - FEATURES=32 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=32 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=33 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=33 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=34 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=34 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=35 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=35 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=36 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=36 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=37 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=37 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=38 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=38 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=39 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=39 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=40 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=40 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=41 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=41 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=42 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=42 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=43 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=43 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=44 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=44 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=45 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=45 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=46 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=46 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=47 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=47 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=48 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=48 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=49 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=49 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=50 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=50 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=51 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=51 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=52 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=52 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=53 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=53 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=54 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=54 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=55 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=55 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=56 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=56 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=57 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=57 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=58 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=58 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=59 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=59 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=60 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=60 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=61 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=61 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=62 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=62 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=63 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO -# - FEATURES=63 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=NO - # - FEATURES=64 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=64 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=65 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=65 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=66 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=66 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=67 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=67 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=68 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=68 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=69 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=69 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=70 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=70 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=71 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=71 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=72 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=72 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=73 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=73 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=74 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=74 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=75 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=75 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=76 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=76 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=77 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=77 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=78 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=78 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=79 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=79 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=NO - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=80 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=80 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=81 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=81 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=82 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=82 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=83 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=83 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=84 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=84 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=85 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=85 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=86 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=86 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=87 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=87 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=NO - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=88 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=88 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=89 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=89 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=90 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=90 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=91 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=91 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=YES - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=92 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=92 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=93 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=93 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=NO - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=94 - # BUILD_SHARED=NO - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=94 - # BUILD_SHARED=YES - # NO_FILES=YES - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=95 - # BUILD_SHARED=NO - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES - # - FEATURES=95 - # BUILD_SHARED=YES - # NO_FILES=NO - # ENABLE_SSL=YES - # NO_CGI=NO - # ENABLE_IPV6=YES - # ENABLE_WEBSOCKETS=YES - # ENABLE_LUA=NO - # ENABLE_DUKTAPE=YES -# - FEATURES=96 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=96 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=97 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=97 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=98 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=98 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=99 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=99 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=100 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=100 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=101 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=101 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=102 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=102 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=103 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=103 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=104 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=104 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=105 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=105 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=106 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=106 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=107 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=107 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=108 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=108 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=109 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=109 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=110 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=110 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=111 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=111 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=NO -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=112 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=112 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=113 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=113 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=114 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=114 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=115 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=115 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=116 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=116 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=117 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=117 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=118 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=118 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=119 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=119 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=NO -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=120 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=120 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=121 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=121 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=122 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=122 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=123 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=123 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=YES -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=124 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=124 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=125 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=125 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=NO -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=126 -# BUILD_SHARED=NO -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=126 -# BUILD_SHARED=YES -# NO_FILES=YES -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=127 -# BUILD_SHARED=NO -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES -# - FEATURES=127 -# BUILD_SHARED=YES -# NO_FILES=NO -# ENABLE_SSL=YES -# NO_CGI=NO -# ENABLE_IPV6=YES -# ENABLE_WEBSOCKETS=YES -# ENABLE_LUA=YES -# ENABLE_DUKTAPE=YES - -addons: - apt: - packages: - - cmake - - openssl - - libssl-dev - sources: - - kubuntu-backports - -before_install: - - cmake --version - -install: - - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then - PATH=~/.local/bin:${PATH}; - pip install --user --upgrade pip; - pip install --user cpp-coveralls; - fi - -before_script: - # Check some settings of the build server - - uname -a - - pwd - #- ls -l - #- ifconfig - #- /sbin/ip addr show - # Generate the build scripts with CMake - - mkdir output - - gcc test/cgi_test.c -o output/cgi_test.cgi - - cd output - - cmake --version - - cmake - -G "Unix Makefiles" - -DCMAKE_BUILD_TYPE=${BUILD_TYPE} - -DBUILD_SHARED_LIBS=${BUILD_SHARED} - "-DCIVETWEB_THIRD_PARTY_DIR=${HOME}/third-party" - -DCIVETWEB_ENABLE_THIRD_PARTY_OUTPUT=YES - -DCIVETWEB_ENABLE_SSL=${ENABLE_SSL} - -DCIVETWEB_DISABLE_CGI=${NO_CGI} - -DCIVETWEB_SERVE_NO_FILES=${NO_FILES} - -DCIVETWEB_ENABLE_SSL_DYNAMIC_LOADING=${ENABLE_SSL_DYNAMIC_LOADING} - -DCIVETWEB_ENABLE_WEBSOCKETS=${ENABLE_WEBSOCKETS} - -DCIVETWEB_ENABLE_CXX=${ENABLE_CXX} - -DCIVETWEB_ENABLE_IPV6=${ENABLE_IPV6} - -DCIVETWEB_ENABLE_LUA=${ENABLE_LUA} - -DCIVETWEB_ENABLE_LUA_SHARED=${ENABLE_LUA_SHARED} - -DCIVETWEB_ENABLE_DUKTAPE=${ENABLE_DUKTAPE} - -DCIVETWEB_DISABLE_CACHING=${NO_CACHING} - -DCIVETWEB_C_STANDARD=${C_STANDARD} - -DCIVETWEB_CXX_STANDARD=${CXX_STANDARD} - .. - - ls -la - -cache: - directories: - - $HOME/third-party - -matrix: - fast_finish: true - exclude: - # Exclude GCC from OS X builds because it's actually clang so it's just duplicate builds - - os: osx - compiler: gcc - -script: - - CTEST_OUTPUT_ON_FAILURE=1 make all test - -# Coveralls options: https://github.com/eddyxu/cpp-coveralls/blob/master/README.md -after_success: - - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then - coveralls --include src --exclude src/main.c --exclude src/third_party --include include --gcov-options '\-lp' --root .. --build-root .; - fi +############################################################################## +# Travis version specific build environment specification +############################################################################## + +# The "precise" build environment on Travis is in the process of being decommissioned +# see https://blog.travis-ci.com/2017-08-31-trusty-as-default-status +# The "precise=true"+"sudo=required" environment seems to lack IPv6 support. +# According to some tests, all "sudo=required" environments do not support IPv6, see +# https://github.com/travis-ci/travis-ci/issues/8361#issuecomment-328263113 +# The container environments for "sudo=false" support IPv6 localhost [::1] +# connections for server/client test. Thus, all tests with ENABLE_IPV6=YES +# + + +############################################################################## +# Project specific settings +############################################################################## + +language: c + +cache: + directories: + - $HOME/third-party + +osx_image: xcode8 + +addons: + apt: + packages: + - cmake + - openssl + - libssl-dev + sources: + - kubuntu-backports + + +before_install: + - if [ "${TRAVIS_OS_NAME}" == "linux" ]; then + mkdir $HOME/usr; + export PATH="$HOME/usr/bin:$PATH"; + wget https://cmake.org/files/v3.7/cmake-3.7.2-Linux-x86_64.sh --no-check-certificate; + chmod +x cmake-3.7.2-Linux-x86_64.sh; + ./cmake-3.7.2-Linux-x86_64.sh --prefix=$HOME/usr --exclude-subdir --skip-license; + fi + - cmake --version + + +install: + - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then + PATH=~/.local/bin:${PATH}; + pip install --user --upgrade pip; + pip install --user cpp-coveralls; + fi + +before_script: + # Check some settings of the build server (operating system, IPv6 availability, directory) + - uname -a + - ifconfig + - pwd + - ls -la + - if [ "${TRAVIS_OS_NAME}" == "linux" ]; then + apt-cache search gcc | grep "GNU C compiler"; + apt-cache search clang | grep compiler; + fi + - if [[ "${BUILD_TYPE}" == "OSX_OPENSSL_1_1" ]]; then brew install openssl@1.1 ;fi + # Generate the build scripts with CMake + - mkdir output + - gcc test/cgi_test.c -o output/cgi_test.cgi + - cd output + - cmake --version + - cmake + -G "Unix Makefiles" + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} + -DBUILD_SHARED_LIBS=${BUILD_SHARED} + "-DCIVETWEB_THIRD_PARTY_DIR=${HOME}/third-party" + -DCIVETWEB_ENABLE_THIRD_PARTY_OUTPUT=YES + -DCIVETWEB_ENABLE_SSL=${ENABLE_SSL} + -DCIVETWEB_DISABLE_CGI=${NO_CGI} + -DCIVETWEB_SERVE_NO_FILES=${NO_FILES} + -DCIVETWEB_ENABLE_SSL_DYNAMIC_LOADING=${ENABLE_SSL_DYNAMIC_LOADING} + -DCIVETWEB_SSL_OPENSSL_API_1_1=${OPENSSL_1_1} + -DCIVETWEB_ENABLE_WEBSOCKETS=${ENABLE_WEBSOCKETS} + -DCIVETWEB_ENABLE_CXX=${ENABLE_CXX} + -DCIVETWEB_ENABLE_IPV6=${ENABLE_IPV6} + -DCIVETWEB_ENABLE_SERVER_STATS=${ENABLE_SERVER_STATS} + -DCIVETWEB_ENABLE_LUA=${ENABLE_LUA} + -DCIVETWEB_ENABLE_LUA_SHARED=${ENABLE_LUA_SHARED} + -DCIVETWEB_ENABLE_DUKTAPE=${ENABLE_DUKTAPE} + -DCIVETWEB_DISABLE_CACHING=${NO_CACHING} + -DCIVETWEB_C_STANDARD=${C_STANDARD} + -DCIVETWEB_CXX_STANDARD=${CXX_STANDARD} + -DCIVETWEB_ALLOW_WARNINGS=${ALLOW_WARNINGS} + ${ADDITIONAL_CMAKE_ARGS} + .. + - ls -la + +script: + - if [ "${MACOSX_PACKAGE}" == "1" ]; then + cd "${TRAVIS_BUILD_DIR}"; + make -f Makefile.osx package; + else + CTEST_OUTPUT_ON_FAILURE=1 make all test; + fi + +# Coveralls options: https://github.com/eddyxu/cpp-coveralls/blob/master/README.md +after_success: + - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then + coveralls --include src --exclude src/main.c --exclude src/third_party --include include --gcov-options '\-lp' --root .. --build-root .; + bash <(curl -s https://codecov.io/bash); + fi + + +############################################################################## +# build matrix (auto generated) +############################################################################## + + +matrix: + fast_finish: false + include: + + - dist: trusty + sudo: false + os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - clang-3.8 + env: + idx=1 + N=Clang3.8-Linux-Minimal-Debug + MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + BUILD_TYPE=Debug + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=0 + BUILD_SHARED=NO + NO_FILES=YES + ENABLE_SSL=NO + NO_CGI=YES + ENABLE_IPV6=NO + ENABLE_WEBSOCKETS=NO + ENABLE_SERVER_STATS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + + - dist: trusty + sudo: false + os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - clang-3.8 + env: + idx=2 + N=Clang3.8-Linux-Default-Release + MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + BUILD_TYPE=Release + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=7 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=NO + ENABLE_WEBSOCKETS=NO + ENABLE_SERVER_STATS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + + - dist: trusty + sudo: false + os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - clang-3.8 + env: + idx=3 + N=Clang3.8-Linux-Default-Release + MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + BUILD_TYPE=Release + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=7 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=NO + ENABLE_WEBSOCKETS=NO + ENABLE_SERVER_STATS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + + - dist: trusty + sudo: false + os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - clang-3.8 + env: + idx=4 + N=Clang3.8-Linux-Complete-NoLua-Release + MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + BUILD_TYPE=Release + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=31 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=YES + ENABLE_WEBSOCKETS=YES + ENABLE_SERVER_STATS=YES + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=YES + ALLOW_WARNINGS=YES + + + - dist: trusty + sudo: false + os: linux + compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: + idx=5 + N=GCC5-Linux-Complete-NoLua-Release + MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" + BUILD_TYPE=Release + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=31 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=YES + ENABLE_WEBSOCKETS=YES + ENABLE_SERVER_STATS=YES + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=YES + ALLOW_WARNINGS=YES + + - os: linux + compiler: gcc + env: + idx=6 + N=GCCAnyVersion-Linux-Coverage + BUILD_TYPE=Coverage + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=31 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=YES + ENABLE_WEBSOCKETS=YES + ENABLE_SERVER_STATS=YES + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + + - os: osx + compiler: clang + env: + idx=7 + N=Clang-OSX-Complete-NoLua-Release + BUILD_TYPE=Release + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=31 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=YES + ENABLE_WEBSOCKETS=YES + ENABLE_SERVER_STATS=YES + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=YES + ALLOW_WARNINGS=YES + + - + os: osx + compiler: clang + env: + idx=8 + N=Clang-OSX-Complete-NoLua-Release-OpenSSL_1_1_NoDynLoad + BUILD_TYPE=OSX_OPENSSL_1_1 + ENABLE_SSL_DYNAMIC_LOADING=NO + OPENSSL_1_1=YES + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=31 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=YES + ENABLE_WEBSOCKETS=YES + ENABLE_SERVER_STATS=YES + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=YES + ALLOW_WARNINGS=YES + OPENSSL_ROOT_DIR="/usr/local/opt/openssl@1.1" + LDFLAGS="-L${OPENSSL_ROOT_DIR}/lib" + CFLAGS="-I${OPENSSL_ROOT_DIR}/include" + ADDITIONAL_CMAKE_ARGS="-DCMAKE_SHARED_LINKER_FLAGS=${LDFLAGS} -DCMAKE_C_FLAGS=${CFLAGS}" + PATH="${OPENSSL_ROOT_DIR}/bin:$PATH" + DYLD_LIBRARY_PATH="${OPENSSL_ROOT_DIR}/lib:${DYLD_LIBRARY_PATH}" + + - dist: trusty + sudo: false + os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-5.0 + packages: + - clang-5.0 + env: + idx=9 + N=Clang50-Linux-Default-Shared + BUILD_TYPE=Debug + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=7 + BUILD_SHARED=YES + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=NO + ENABLE_WEBSOCKETS=NO + ENABLE_SERVER_STATS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + + - + os: linux + dist: precise + sudo: required + compiler: clang + env: + idx=10 + N=Precise-Clang-Linux-Default + BUILD_TYPE=Debug + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=7 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=NO + ENABLE_WEBSOCKETS=NO + ENABLE_SERVER_STATS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + + - + os: osx + compiler: clang + env: + idx=11 + N=OSX-Package + BUILD_TYPE=Release + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=31 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=YES + ENABLE_WEBSOCKETS=YES + ENABLE_SERVER_STATS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + MACOSX_PACKAGE=1 + + - dist: trusty + sudo: false + os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-3.8 + packages: + - clang-3.8 + env: + idx=12 + N=Clang-Linux-32bit-Complete-NoLua-Release + ARCH=x86 + BUILD_TYPE=Release + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=31 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=YES + ENABLE_WEBSOCKETS=YES + ENABLE_SERVER_STATS=YES + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=YES + ALLOW_WARNINGS=YES + MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + + +### Test all build types: +# According to CMakeLists, options are: +# None Debug Release RelWithDebInfo MinSizeRel Coverage + + - + os: linux + compiler: clang + env: + idx=13 + N=NoSslDynamicLoading + BUILD_TYPE=Release + ENABLE_SSL_DYNAMIC_LOADING=NO + OPENSSL_1_1=NO + ENABLE_CXX=NO + C_STANDARD=auto + CXX_STANDARD=auto + ENABLE_LUA_SHARED=NO + FEATURES=31 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=YES + ENABLE_WEBSOCKETS=YES + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + + - + os: linux + compiler: gcc + env: + idx=14 + N=GCCLinuxDefault_Debug + BUILD_TYPE=Debug + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=7 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=NO + ENABLE_WEBSOCKETS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + + - + os: linux + compiler: gcc + env: + idx=15 + N=GCCLinuxDefault_RelWithDebInfo + BUILD_TYPE=RelWithDebInfo + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=7 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=NO + ENABLE_WEBSOCKETS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + + - + os: linux + compiler: gcc + env: + idx=16 + N=GCCLinuxDefault_MinSizeRel + BUILD_TYPE=MinSizeRel + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=7 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=NO + ENABLE_WEBSOCKETS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + + - + os: linux + compiler: gcc + env: + idx=17 + N=GCCLinuxDefault_None + BUILD_TYPE=None + ENABLE_SSL_DYNAMIC_LOADING=YES + OPENSSL_1_1=NO + ENABLE_CXX=NO + ENABLE_LUA_SHARED=NO + C_STANDARD=auto + CXX_STANDARD=auto + FEATURES=7 + BUILD_SHARED=NO + NO_FILES=NO + ENABLE_SSL=YES + NO_CGI=NO + ENABLE_IPV6=NO + ENABLE_WEBSOCKETS=NO + ENABLE_LUA=NO + ENABLE_DUKTAPE=NO + NO_CACHING=NO + ALLOW_WARNINGS=YES + + +#### Now all define combinations, but only for Linux clang +##### Generated with Lua: +# +# function YN(i,b) +# local bits = {} +# while (i > 0.5) do +# i = math.floor(i) +# bits[#bits+1] = (math.mod(i, 2) == 1) +# i = i/2 +# end +# if (bits[b]) then +# return "YES" +# end +# return "NO" +# end +# function INV(t) +# if t=="YES" then +# return "NO" +# elseif t=="NO" then +# return "YES" +# else +# assert("ERROR in INV!") +# end +# end +# for i=0,511 do +# if (YN(i, 6)=="NO") and (YN(i, 7)=="NO") then +# print(" -") +# print(" os: linux") +# print(" compiler: clang") +# print(" env:") +# print(" N=C" .. tostring(i) .. "_") +# print(" BUILD_TYPE=Release") +# print(" ENABLE_SSL_DYNAMIC_LOADING=YES") +# print(" OPENSSL_1_1=NO") +# print(" ENABLE_CXX=NO") +# print(" C_STANDARD=auto") +# print(" CXX_STANDARD=auto") +# print(" ENABLE_LUA_SHARED=NO") +# print(" FEATURES=" .. tostring(i)) +# print(" BUILD_SHARED=NO") +# print(" NO_FILES=" .. INV(YN(i, 1))) +# print(" ENABLE_SSL=" .. YN(i, 2)) +# print(" NO_CGI=" .. INV(YN(i, 3))) +# print(" ENABLE_IPV6=" .. YN(i, 4)) +# print(" ENABLE_WEBSOCKETS=" .. YN(i, 5)) +# print(" ENABLE_LUA=" .. YN(i, 6)) +# print(" ENABLE_DUKTAPE=" .. YN(i, 7)) +# print(" NO_CACHING=" .. INV(YN(i, 8))) +# print(" ENABLE_SERVER_STATS=" .. YN(i, 9)) +# print("") +# end +# end +# + +# TODO: Regenerate this matrix, once a stable Travis build is re-established + + diff --git a/ceph/src/civetweb/CMakeLists.txt b/ceph/src/civetweb/CMakeLists.txt index 7421e50ad..2c08bd28e 100644 --- a/ceph/src/civetweb/CMakeLists.txt +++ b/ceph/src/civetweb/CMakeLists.txt @@ -26,7 +26,7 @@ include(CMakeDependentOption) # Set up the project project (civetweb) -set(CIVETWEB_VERSION "1.7.0" CACHE STRING "The version of the civetweb library") +set(CIVETWEB_VERSION "1.10.0" CACHE STRING "The version of the civetweb library") string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CIVETWEB_VERSION_MATCH "${CIVETWEB_VERSION}") if ("${CIVETWEB_VERSION_MATCH}" STREQUAL "") message(FATAL_ERROR "Must specify a semantic version: major.minor.patch") @@ -48,12 +48,6 @@ endif() # C++ wrappers option(CIVETWEB_ENABLE_THIRD_PARTY_OUTPUT "Shows the output of third party dependency processing" OFF) -# Max Request Size -set(CIVETWEB_MAX_REQUEST_SIZE 16384 CACHE STRING - "The largest amount of content bytes allowed in a request") -set_property(CACHE CIVETWEB_MAX_REQUEST_SIZE PROPERTY VALUE ${CIVETWEB_MAX_REQUEST_SIZE}) -message(STATUS "Max Request Size - ${CIVETWEB_MAX_REQUEST_SIZE}") - # Thread Stack Size set(CIVETWEB_THREAD_STACK_SIZE 102400 CACHE STRING "The stack size in bytes for each thread created") @@ -84,22 +78,39 @@ message(STATUS "IP Version 6 - ${CIVETWEB_ENABLE_IPV6}") option(CIVETWEB_ENABLE_WEBSOCKETS "Enable websockets connections" OFF) message(STATUS "Websockets support - ${CIVETWEB_ENABLE_WEBSOCKETS}") +# Server statistics support +option(CIVETWEB_ENABLE_SERVER_STATS "Enable server statistics" OFF) +message(STATUS "Server statistics support - ${CIVETWEB_ENABLE_SERVER_STATS}") + # Memory debugging option(CIVETWEB_ENABLE_MEMORY_DEBUGGING "Enable the memory debugging features" OFF) message(STATUS "Memory Debugging - ${CIVETWEB_ENABLE_MEMORY_DEBUGGING}") +# ASAN in debug mode (-fsanitize=address, etc) +option(CIVETWEB_ENABLE_ASAN "Enable ASAN in debug mode" ON) +message(STATUS "ASAN in debug mode - ${CIVETWEB_ENABLE_ASAN}") + +# ARCH flag +option(CIVETWEB_ARCH "Force 32/64 bit architecture" OFF) +message(STATUS "Force x32 / x64 architecture - ${CIVETWEB_ARCH}") + # LUA CGI support option(CIVETWEB_ENABLE_LUA "Enable Lua CGIs" OFF) message(STATUS "Lua CGI support - ${CIVETWEB_ENABLE_LUA}") +# Enable installing CivetWeb executables +option(CIVETWEB_INSTALL_EXECUTABLE "Enable installing CivetWeb executable" ON) +mark_as_advanced(FORCE CIVETWEB_INSTALL_EXECUTABLE) # Advanced users can disable +message(STATUS "Executable installation - ${CIVETWEB_INSTALL_EXECUTABLE}") + # Allow builds to complete with warnings (do not set -Werror) -if (LINUX) -# CivetWeb Linux support is stable: Builds must be free from warnings. - option(CIVETWEB_ALLOW_WARNINGS "Do not stop build if there are warnings" OFF) -else() -# CivetWeb Linux support for other systems is in a setup phase. - option(CIVETWEB_ALLOW_WARNINGS "Do not stop build if there are warnings" ON) -endif() +# CivetWeb Linux support is stable: +# Builds for GCC 4.6 and clang 3.4 are free from warnings. +# However, GCC introduced a couple of new, partially idiotic warnings, +# that can not be disabled using a #pragma directive. +# It seems unreasonable to have all GCC versions warning free, but only +# some selected ones. +option(CIVETWEB_ALLOW_WARNINGS "Do not stop build if there are warnings" ON) message(STATUS "Build if there are warnings - ${CIVETWEB_ALLOW_WARNINGS}") # Link to the shared LUA library @@ -188,6 +199,10 @@ message(STATUS "Duktape CGI support - ${CIVETWEB_ENABLE_DUKTAPE}") option(CIVETWEB_ENABLE_SSL "Enables the secure socket layer" ON) message(STATUS "SSL support - ${CIVETWEB_ENABLE_SSL}") +# OpenSSL 1.1 API +option(CIVETWEB_SSL_OPENSSL_API_1_1 "Use the OpenSSL 1.1 API" OFF) +message(STATUS "Compile for OpenSSL 1.1 API - ${CIVETWEB_SSL_OPENSSL_API_1_1}") + # Dynamically load or link the SSL libraries cmake_dependent_option( CIVETWEB_ENABLE_SSL_DYNAMIC_LOADING "Dynamically loads the SSL library rather than linking it" ON @@ -254,17 +269,26 @@ if ("${CIVETWEB_C_STANDARD}" STREQUAL "auto") else() add_c_compiler_flag(-std=${CIVETWEB_C_STANDARD}) endif() + +#Warnings: enable everything add_c_compiler_flag(-Wall) add_c_compiler_flag(-Wextra) add_c_compiler_flag(-Wshadow) -add_c_compiler_flag(-Wsign-conversion) +add_c_compiler_flag(-Wconversion) add_c_compiler_flag(-Wmissing-prototypes) add_c_compiler_flag(-Weverything) -add_c_compiler_flag(/W4) -add_c_compiler_flag(-Wno-padded) +add_c_compiler_flag(-Wparentheses) +add_c_compiler_flag(/W4) # VisualStudio highest warning level + +#Warnings: Disable some warnings +add_c_compiler_flag(-Wno-padded) # padding in structures by compiler +add_c_compiler_flag(-Wno-unused-macros) # so what? +add_c_compiler_flag(-Wno-reserved-id-macros) # for system headers +add_c_compiler_flag(-Wno-format-nonliteral) # printf(myFormatStringVar, ...) +add_c_compiler_flag(-Wno-date-time) # using __DATE__ once +add_c_compiler_flag(-Wno-cast-qual) # const cast add_c_compiler_flag(/Wd4820) # padding -add_c_compiler_flag(-Wno-unused-macros) -add_c_compiler_flag(-Wno-format-nonliteral) + if (MINGW) add_c_compiler_flag(-Wno-format) endif() @@ -276,11 +300,13 @@ add_c_compiler_flag(-pedantic-errors) add_c_compiler_flag(-fvisibility=hidden) add_c_compiler_flag(-fstack-protector-strong RELEASE) add_c_compiler_flag(-flto RELEASE) +if (${CIVETWEB_ENABLE_ASAN}) add_c_compiler_flag(-fsanitize=undefined DEBUG) add_c_compiler_flag(-fsanitize=address DEBUG) if (HAVE_C_FLAG_FSANITIZE_ADDRESS) add_c_compiler_flag(-static-asan DEBUG) endif() +endif() add_c_compiler_flag(-fstack-protector-all DEBUG) if (MINGW) add_c_compiler_flag(-mwindows) @@ -343,11 +369,13 @@ if (CIVETWEB_ENABLE_CXX) add_cxx_compiler_flag(-fvisibility=hidden) add_cxx_compiler_flag(-fstack-protector-strong RELEASE) add_cxx_compiler_flag(-flto RELEASE) + if (${CIVETWEB_ENABLE_ASAN}) add_cxx_compiler_flag(-fsanitize=undefined DEBUG) add_cxx_compiler_flag(-fsanitize=address DEBUG) if (HAVE_CXX_FLAG_FSANITIZE_ADDRESS) add_cxx_compiler_flag(-static-asan DEBUG) endif() + endif() add_cxx_compiler_flag(-fstack-protector-all DEBUG) if (MINGW) add_cxx_compiler_flag(-mwindows) @@ -358,22 +386,19 @@ if (CIVETWEB_ENABLE_CXX) add_cxx_compiler_flag(--coverage COVERAGE) endif() -# Check the headers we need -check_include_files(stdint.h HAVE_STDINT) - # Set up the definitions if (${CMAKE_BUILD_TYPE} MATCHES "[Dd]ebug") add_definitions(-DDEBUG) endif() -if (HAVE_STDINT) - add_definitions(-DHAVE_STDINT) -endif() if (CIVETWEB_ENABLE_IPV6) add_definitions(-DUSE_IPV6) endif() if (CIVETWEB_ENABLE_WEBSOCKETS) add_definitions(-DUSE_WEBSOCKET) endif() +if (CIVETWEB_ENABLE_SERVER_STATS) + add_definitions(-DUSE_SERVER_STATS) +endif() if (CIVETWEB_SERVE_NO_FILES) add_definitions(-DNO_FILES) endif() @@ -404,8 +429,19 @@ else() add_definitions(-DCRYPTO_LIB="${CIVETWEB_SSL_CRYPTO_LIB}") endif() endif() +if(CIVETWEB_SSL_OPENSSL_API_1_1) + add_definitions(-DOPENSSL_API_1_1) +endif() add_definitions(-DUSE_STACK_SIZE=${CIVETWEB_THREAD_STACK_SIZE}) -add_definitions(-DMAX_REQUEST_SIZE=${CIVETWEB_MAX_REQUEST_SIZE}) + +# Set 32 or 64 bit environment +if (${CMAKE_ARCH} MATCHES "[Xx]86") +add_c_compiler_flag(-m32) +endif() +if (${CMAKE_ARCH} MATCHES "[Xx]64") +add_c_compiler_flag(-m64) +endif() +# TODO: add support for -march # Build the targets add_subdirectory(src) @@ -414,14 +450,16 @@ add_subdirectory(src) include(CTest) if (BUILD_TESTING) # Check unit testing framework Version - set(CIVETWEB_CHECK_VERSION 0.10.0 CACHE STRING + set(CIVETWEB_CHECK_VERSION 0.11.0 CACHE STRING "The version of Check unit testing framework to build and include statically") set_property(CACHE CIVETWEB_CHECK_VERSION PROPERTY VALUE ${CIVETWEB_CHECK_VERSION}) message(STATUS "Check Unit Testing Framework Version - ${CIVETWEB_CHECK_VERSION}") mark_as_advanced(CIVETWEB_CHECK_VERSION) # Check unit testing framework Verification Hash - set(CIVETWEB_CHECK_MD5_HASH 67a34c40b5bc888737f4e5ae82e9939f CACHE STRING + # Hash for Check 0.10.0: 67a34c40b5bc888737f4e5ae82e9939f + # Hash for Check 0.11.0: 1b14ee307dca8e954a8219c34484d7c4 + set(CIVETWEB_CHECK_MD5_HASH 1b14ee307dca8e954a8219c34484d7c4 CACHE STRING "The hash of Check unit testing framework archive to be downloaded") set_property(CACHE CIVETWEB_CHECK_MD5_HASH PROPERTY VALUE ${CIVETWEB_CHECK_MD5_HASH}) mark_as_advanced(CIVETWEB_CHECK_MD5_HASH) diff --git a/ceph/src/civetweb/CREDITS.md b/ceph/src/civetweb/CREDITS.md index c7b65debf..4e4c98745 100644 --- a/ceph/src/civetweb/CREDITS.md +++ b/ceph/src/civetweb/CREDITS.md @@ -1,10 +1,15 @@ # Civetweb Contributors +* Abhishek Lekshmanan +* Adam Bailey +* Alan Somers * Alex Kozlov * bel2125 * Ben M. Ward -* brett +* BigJoe * Bjoern Petri +* Braedy Kuzma +* brett * Brian Lambert * Brian Spratke * cdbishop @@ -16,16 +21,23 @@ * Daniel Oaks * Daniel Rempel * Danny Al-Gaaf +* Dave Brower * David Arnold * David Loffredo * Dialga +* ehlertjd * Eric Tsau +* Erik Beran +* extergnoto * F-Secure Corporation +* feneuilflo * Fernando G. Aranda * Grahack * grenclave +* grunk * hansipie * HariKamath Kamath +* Henry Chang * Jack * Jacob Skillin * Jan Willem Janssen @@ -40,10 +52,13 @@ * Jordan Shelley * Joshua Boyd * Joshua D. Boyd +* kakwa * kalphamon * Keith Kyzivat +* Kevin Branigan * Kevin Wojniak * Kimmo Mustonen +* Lammert Bies * Lawrence * Li Peng * Lianghui @@ -55,33 +70,51 @@ * Matt Clarkson * mingodad * Morgan McGuire +* mrdvlpr.xnu * Neil Jensen * Nick Hildebrant * Nigel Stewart * nihildeb * No Face Press +* palortoff +* Patrick Drechsler +* Patrick Trinkle * Paul Sokolovsky +* Paulo Brizolara +* pavel.pimenov +* PavelVozenilek * Perttu Ahola +* Peter Foerster * Philipp Friedenberger * Philipp Hasper * Red54 * Richard Screene +* pkvamme * Sage Weil * Sangwhan Moon -* shantanugadgil +* Saumitra Vikram * Scott Nations +* sgmesservey +* shantanugadgil +* Simon Hailes +* slidertom +* SpaceLord * sunfch * thewaterymoon +* THILMANT, Bernard * Thomas Davis * tnoho * Toni Wilk * Ulrich Hertlein * Walt Steverson +* webxer * William Greathouse +* xeoshow +* xtne6f * Yehuda Sadeh # Mongoose Contributors -Civetweb is based on the Mongoose code. The following users contributed to the original Mongoose release between 2010 and 2013. This list was generated from the Mongoose GIT logs. It does not contain contributions from the Mongoose mailing list. There is no record for contributors prior to 2010. +CivetWeb is based on the Mongoose code. The following users contributed to the original Mongoose release between 2010 and 2013. This list was generated from the Mongoose GIT logs. It does not contain contributions from the Mongoose mailing list. There is no record for contributors prior to 2010. * Sergey Lyubka * Arnout Vandecappelle (Essensium/Mind) @@ -131,3 +164,4 @@ Civetweb is based on the Mongoose code. The following users contributed to the * tayS * test * valenok + diff --git a/ceph/src/civetweb/LICENSE.md b/ceph/src/civetweb/LICENSE.md index 263690e51..be6ae19b9 100644 --- a/ceph/src/civetweb/LICENSE.md +++ b/ceph/src/civetweb/LICENSE.md @@ -11,7 +11,7 @@ Civetweb License ### Included with all features. -> Copyright (c) 2013-2015 The CivetWeb developers ([CREDITS.md](https://github.com/civetweb/civetweb/blob/master/CREDITS.md)) +> Copyright (c) 2013-2017 The CivetWeb developers ([CREDITS.md](https://github.com/civetweb/civetweb/blob/master/CREDITS.md)) > > Copyright (c) 2004-2013 Sergey Lyubka > @@ -206,5 +206,3 @@ https://github.com/svaarala/duktape/blob/master/LICENSE.txt > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > THE SOFTWARE. - - diff --git a/ceph/src/civetweb/Makefile b/ceph/src/civetweb/Makefile index 93f1bd134..fdc015f9e 100644 --- a/ceph/src/civetweb/Makefile +++ b/ceph/src/civetweb/Makefile @@ -60,14 +60,14 @@ BUILD_DIRS += $(BUILD_DIR)/test endif # only set main compile options if none were chosen -CFLAGS += -Wall -Wextra -Wshadow -Wformat-security -Winit-self -Wmissing-prototypes -O2 -D$(TARGET_OS) -Iinclude $(COPT) -DUSE_STACK_SIZE=102400 +CFLAGS += -Wall -Wextra -Wshadow -Wformat-security -Winit-self -Wmissing-prototypes -D$(TARGET_OS) -Iinclude $(COPT) -DUSE_STACK_SIZE=102400 LIBS = -lpthread -lm ifdef WITH_DEBUG - CFLAGS += -g -DDEBUG_ENABLED + CFLAGS += -g -DDEBUG else - CFLAGS += -DNDEBUG + CFLAGS += -O2 -DNDEBUG endif ifdef WITH_CPP @@ -77,6 +77,15 @@ else LCC = $(CC) endif +ifdef WITH_ALL + WITH_WEBSOCKET = 1 + WITH_IPV6 = 1 + WITH_LUA = 1 + WITH_DUKTAPE = 1 + WITH_SERVER_STATS = 1 + #WITH_CPP is not defined, ALL means only real features, not wrappers +endif + ifdef WITH_LUA_SHARED WITH_LUA = 1 endif @@ -110,6 +119,16 @@ endif ifdef WITH_WEBSOCKET CFLAGS += -DUSE_WEBSOCKET endif +ifdef WITH_WEBSOCKETS + CFLAGS += -DUSE_WEBSOCKET +endif + +ifdef WITH_SERVER_STAT + CFLAGS += -DUSE_SERVER_STATS +endif +ifdef WITH_SERVER_STATS + CFLAGS += -DUSE_SERVER_STATS +endif ifdef CONFIG_FILE CFLAGS += -DCONFIG_FILE=\"$(CONFIG_FILE)\" @@ -180,6 +199,7 @@ help: @echo " WITH_DEBUG=1 build with GDB debug support" @echo " WITH_IPV6=1 with IPV6 support" @echo " WITH_WEBSOCKET=1 build with web socket support" + @echo " WITH_SERVER_STATS=1 build includes support for server statistics" @echo " WITH_CPP=1 build library with c++ classes" @echo " CONFIG_FILE=file use 'file' as the config file" @echo " CONFIG_FILE2=file use 'file' as the backup config file" @@ -198,7 +218,6 @@ help: @echo " NO_SSL_DL link against system libssl library" @echo " NO_FILES do not serve files from a directory" @echo " NO_CACHING disable caching (usefull for systems without timegm())" - @echo " MAX_REQUEST_SIZE maximum header size, default 16384" @echo "" @echo " Variables" @echo " TARGET_OS='$(TARGET_OS)'" @@ -247,7 +266,7 @@ slib: lib$(CPROG).$(SHARED_LIB) clean: $(RMRF) $(BUILD_DIR) - $(eval version=$(shell grep "define CIVETWEB_VERSION" include/civetweb.h | sed 's|.*VERSION "\(.*\)"|\1|g')) + $(eval version=$(shell grep -w "define CIVETWEB_VERSION" include/civetweb.h | sed 's|.*VERSION "\(.*\)"|\1|g')) $(eval major=$(shell echo $(version) | cut -d'.' -f1)) $(RMRF) lib$(CPROG).a $(RMRF) lib$(CPROG).so @@ -269,7 +288,7 @@ lib$(CPROG).a: $(LIB_OBJECTS) lib$(CPROG).so: CFLAGS += -fPIC lib$(CPROG).so: $(LIB_OBJECTS) - $(eval version=$(shell grep "define CIVETWEB_VERSION" include/civetweb.h | sed 's|.*VERSION "\(.*\)"|\1|g')) + $(eval version=$(shell grep -w "define CIVETWEB_VERSION" include/civetweb.h | sed 's|.*VERSION "\(.*\)"|\1|g')) $(eval major=$(shell echo $(version) | cut -d'.' -f1)) $(LCC) -shared -Wl,-soname,$@.$(major) -o $@.$(version).0 $(CFLAGS) $(LDFLAGS) $(LIB_OBJECTS) ln -s -f $@.$(major) $@ @@ -310,3 +329,4 @@ indent: astyle --suffix=none --style=linux --indent=spaces=4 --lineend=linux include/*.h src/*.c src/*.cpp src/*.inl examples/*/*.c examples/*/*.cpp .PHONY: all help build install clean lib so + diff --git a/ceph/src/civetweb/Makefile.osx b/ceph/src/civetweb/Makefile.osx index ffc91ede6..44260e84c 100644 --- a/ceph/src/civetweb/Makefile.osx +++ b/ceph/src/civetweb/Makefile.osx @@ -7,6 +7,9 @@ # security unlock ~/Library/Keychains/login.keychain # See e.g. http://lists.apple.com/archives/apple-cdsa/2008/Jan/msg00027.html +# Civetweb features +WITH_LUA = 1 + PACKAGE = Civetweb BUILD_DIR = out @@ -19,6 +22,7 @@ RESOURCES_DIR = $(CONTENTS_DIR)/Resources OSXBIN_DIR = $(CONTENTS_DIR)/MacOS CIVETWEB_VERSION = $(shell perl -lne '/define\s+CIVETWEB_VERSION\s+"(\S+)"/ and print $$1' include/civetweb.h) +ZIPFILENAME = $(PACKAGE)-$(CIVETWEB_VERSION).zip include Makefile @@ -32,8 +36,7 @@ package: build install -m 755 $(CPROG) $(OSXBIN_DIR)/$(PACKAGE) install -m 644 docs/Installing.md $(DMG_DIR)/Installing.txt install -m 644 LICENSE.md $(DMG_DIR)/License.txt - ln -fs /Applications $(DMG_DIR)/ - hdiutil create $(PACKAGE)-$(CIVETWEB_VERSION).dmg -volname "$(PACKAGE) $(CIVETWEB_VERSION)" -srcfolder $(DMG_DIR) -ov -# @rm -rf $(DMG_DIR) + rm -rf $(ZIPFILENAME) + cd $(DMG_DIR) && zip -r ../../$(ZIPFILENAME) . .PHONY: package diff --git a/ceph/src/civetweb/Qt/CivetWeb.pro b/ceph/src/civetweb/Qt/CivetWeb.pro index 4f77495a9..6d5e1a281 100644 --- a/ceph/src/civetweb/Qt/CivetWeb.pro +++ b/ceph/src/civetweb/Qt/CivetWeb.pro @@ -1,25 +1,34 @@ -TEMPLATE = app -CONFIG += console -CONFIG -= app_bundle -CONFIG -= qt - -SOURCES += \ - ../src/md5.inl \ - ../src/mod_lua.inl \ - ../src/timer.inl \ - ../src/civetweb.c \ - ../src/main.c - -include(deployment.pri) -qtcAddDeployment() - -HEADERS += \ - ../include/civetweb.h - -INCLUDEPATH += \ - ../include/ - -LIBS += -lws2_32 -lComdlg32 - -DEFINES += USE_IPV6 -DEFINES += USE_WEBSOCKET +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +SOURCES += \ + ../src/md5.inl \ + ../src/sha1.inl \ + ../src/handle_form.inl \ + ../src/mod_lua.inl \ + ../src/mod_duktape.inl \ + ../src/timer.inl \ + ../src/civetweb.c \ + ../src/main.c + +#include(deployment.pri) +#qtcAddDeployment() + +HEADERS += \ + ../include/civetweb.h + +INCLUDEPATH += \ + ../include/ + +win32 { +LIBS += -lws2_32 -lComdlg32 -lUser32 -lShell32 -lAdvapi32 +} else { +LIBS += -lpthread -ldl -lm +} + + +DEFINES += USE_IPV6 +DEFINES += USE_WEBSOCKET +DEFINES += USE_SERVER_STATS diff --git a/ceph/src/civetweb/README.md b/ceph/src/civetweb/README.md index 47c35afb7..4a334ca26 100644 --- a/ceph/src/civetweb/README.md +++ b/ceph/src/civetweb/README.md @@ -1,8 +1,10 @@ -![CivetWeb](https://raw.github.com/civetweb/civetweb/master/resources/civetweb_64x64.png "CivetWeb") CivetWeb +![CivetWeb](https://raw.githubusercontent.com/civetweb/civetweb/master/resources/civetweb_64x64.png "CivetWeb") CivetWeb ======= **The official home of CivetWeb is [https://github.com/civetweb/civetweb](https://github.com/civetweb/civetweb)** +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) +[![GitHub contributors](https://img.shields.io/github/contributors/civetweb/civetweb.svg)](https://github.com/civetweb/civetweb/blob/master/CREDITS.md) Continuous integration for Linux and OSX ([Travis CI](https://travis-ci.org/civetweb/civetweb)): @@ -12,17 +14,21 @@ Continuous integration for Windows ([AppVeyor](https://ci.appveyor.com/project/c [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/civetweb/civetweb?svg=true)](https://ci.appveyor.com/project/civetweb/civetweb/branch/master) -Test coverage check ([coveralls](https://coveralls.io/github/civetweb/civetweb)) (currently in a setup phase): +Test coverage check ([coveralls](https://coveralls.io/github/civetweb/civetweb), [codecov](https://codecov.io/gh/civetweb/civetweb/branch/master)) (currently in a setup and evaluation phase): +[![Coveralls](https://img.shields.io/coveralls/civetweb/civetweb.svg?maxAge=3600)]() [![Coverage Status](https://coveralls.io/repos/github/civetweb/civetweb/badge.svg?branch=master)](https://coveralls.io/github/civetweb/civetweb?branch=master) -Static source code analysis ([Coverity](https://scan.coverity.com/projects/5784)): +[![codecov](https://codecov.io/gh/civetweb/civetweb/branch/master/graph/badge.svg)](https://codecov.io/gh/civetweb/civetweb) + + + +Static source code analysis ([Coverity](https://scan.coverity.com/projects/5784)): [![Coverity Scan Build Status](https://scan.coverity.com/projects/5784/badge.svg)](https://scan.coverity.com/projects/5784) - Project Mission ----------------- @@ -37,7 +43,7 @@ It can also be used by end users as a stand-alone web server. It is available as Where to find the official version? ----------------------------------- -End users can download CivetWeb at SourceForge +End users can download CivetWeb releases at SourceForge [https://sourceforge.net/projects/civetweb/](https://sourceforge.net/projects/civetweb/) Developers can contribute to CivetWeb via GitHub @@ -46,8 +52,14 @@ Developers can contribute to CivetWeb via GitHub Trouble tickets should be filed on GitHub [https://github.com/civetweb/civetweb/issues](https://github.com/civetweb/civetweb/issues) -Discussion/support group and announcements are at Google Groups -[https://groups.google.com/d/forum/civetweb](https://groups.google.com/d/forum/civetweb) +Announcements are at Google Groups +[https://groups.google.com/d/forum/civetweb](https://groups.google.com/d/forum/civetweb). Some older support and discussion threads are there as well. However, recently support questions and discussions are usually [GitHub issues](https://github.com/civetweb/civetweb/issues). + +Source releases can be found on GitHub +[https://github.com/civetweb/civetweb/releases](https://github.com/civetweb/civetweb/releases) + +A very brief overview can be found on GitHub Pages +[http://civetweb.github.io/civetweb/](http://civetweb.github.io/civetweb/) Quick start documentation @@ -58,6 +70,7 @@ Quick start documentation - [docs/Building.md](https://github.com/civetweb/civetweb/blob/master/docs/Building.md) - Building the Server (quick start guide) - [docs/Embedding.md](https://github.com/civetweb/civetweb/blob/master/docs/Embedding.md) - Embedding (how to add HTTP support to an existing application) - [docs/OpenSSL.md](https://github.com/civetweb/civetweb/blob/master/docs/OpenSSL.md) - Adding HTTPS (SSL/TLS) support using OpenSSL. +- [API documentation](https://github.com/civetweb/civetweb/tree/master/docs/api) - Additional documentation on the civetweb application programming interface ([civetweb.h](https://github.com/civetweb/civetweb/blob/master/include/civetweb.h)). - [RELEASE_NOTES.md](https://github.com/civetweb/civetweb/blob/master/RELEASE_NOTES.md) - Release Notes - [LICENSE.md](https://github.com/civetweb/civetweb/blob/master/LICENSE.md) - Copyright License @@ -96,33 +109,29 @@ simplicity by a carefully selected list of features: ### Optionally included software - -![Lua](https://raw.github.com/civetweb/civetweb/master/resources/lua-logo.jpg "Lua Logo") - - -![Sqlite3](https://raw.github.com/civetweb/civetweb/master/resources/sqlite3-logo.jpg "Sqlite3 Logo") - - -![LuaFileSystem](https://raw.github.com/civetweb/civetweb/master/resources/luafilesystem-logo.jpg "LuaFileSystem Logo") - - -![LuaSQLite3](https://raw.github.com/civetweb/civetweb/master/resources/luasqlite-logo.jpg "LuaSQLite3 Logo") - - -![LuaXML](https://raw.github.com/civetweb/civetweb/master/resources/luaxml-logo.jpg "LuaXML Logo") - - -![Duktape](https://raw.github.com/civetweb/civetweb/master/resources/duktape-logo.png "Duktape Logo") - +[![Lua](https://raw.githubusercontent.com/civetweb/civetweb/master/resources/lua-logo.jpg "Lua Logo")](http://lua.org) + +[![Sqlite3](https://raw.githubusercontent.com/civetweb/civetweb/master/resources/sqlite3-logo.jpg "Sqlite3 Logo")](http://sqlite.org) + +[![LuaFileSystem](https://raw.githubusercontent.com/civetweb/civetweb/master/resources/luafilesystem-logo.jpg "LuaFileSystem Logo")](http://keplerproject.github.io/luafilesystem/) + +[![LuaSQLite3](https://raw.githubusercontent.com/civetweb/civetweb/master/resources/luasqlite-logo.jpg "LuaSQLite3 Logo")](http://lua.sqlite.org/index.cgi/index) + +[![LuaXML](https://raw.githubusercontent.com/civetweb/civetweb/master/resources/luaxml-logo.jpg "LuaXML Logo")](http://viremo.eludi.net/LuaXML/index.html) + +[![Duktape](https://raw.githubusercontent.com/civetweb/civetweb/master/resources/duktape-logo.png "Duktape Logo")](http://duktape.org) Support ------- -This project is very easy to install and use. Please read the [documentation](https://github.com/civetweb/civetweb/blob/master/docs/) -and have a look at the [examples] (https://github.com/civetweb/civetweb/blob/master/examples/). +This project is very easy to install and use. +Please read the [documentation](https://github.com/civetweb/civetweb/blob/master/docs/) +and have a look at the [examples](https://github.com/civetweb/civetweb/blob/master/examples/). More information may be found on the [mailing list](https://groups.google.com/d/forum/civetweb). +Note: I do not take any liability or warranty for any linked contents. Visit these pages and try the community support suggestions at your own risk. + Contributions --------------- @@ -130,7 +139,8 @@ Contributions Contributions are welcome provided all contributions carry the MIT license. DO NOT APPLY fixes copied from Mongoose to this project to prevent GPL tainting. -Since 2013 CivetWeb and Mongoose are developed independently. By now the code base differs, so patches cannot be safely transfered in either direction. +Since 2013, CivetWeb and Mongoose are developed independently. +By now the code base differs, so patches cannot be safely transfered in either direction. Some guidelines can be found in [docs/Contribution.md](https://github.com/civetweb/civetweb/blob/master/docs/Contribution.md). @@ -142,14 +152,17 @@ Sergey Lyubka (Copyright (c) 2004-2013 Sergey Lyubka, MIT license). However, in August 16, 2013, the [license of Mongoose has been changed](https://groups.google.com/forum/#!topic/mongoose-users/aafbOnHonkI) after writing and distributing the original code this project is based on. -The license change used to be described on the Mongoose Wikipedia page as well, but it's getting deleted there regularly. +The license change and CivetWeb used to be mentioned on the Mongoose +[Wikipedia](https://en.wikipedia.org/wiki/Mongoose_(web_server)) +page as well, but it's getting deleted (and added again) there every +now and then. -CivetWeb has been forked from the last MIT version of Mongoose. -Since 2013, CivetWeb has seen many improvements from various authors -(Copyright (c) 2013-2016 the CivetWeb developers, MIT license). +CivetWeb has been forked from the last MIT version of Mongoose. +Since 2013, CivetWeb has seen many improvements from various authors +(Copyright (c) 2013-2017 the CivetWeb developers, MIT license). A list of authors can be found in [CREDITS.md](https://github.com/civetweb/civetweb/blob/master/CREDITS.md). Using the CivetWeb project ensures the MIT licenses terms are applied and -GPL cannot be imposed on any of this code as long as it is sourced from +GPL cannot be imposed on any of this code, as long as it is sourced from here. This code will remain free with the MIT license protection. diff --git a/ceph/src/civetweb/RELEASE_NOTES.md b/ceph/src/civetweb/RELEASE_NOTES.md index d186a6983..dfae89f16 100644 --- a/ceph/src/civetweb/RELEASE_NOTES.md +++ b/ceph/src/civetweb/RELEASE_NOTES.md @@ -1,3 +1,108 @@ +Release Notes v1.10 +=== +### Objectives: *OpenSSL 1.1 support, add server statistics and diagnostic data* + +Changes +------- + +- Add missing `mg_` or `MG_` to symbols in civetweb.h. Symbols without will be removed a future version. +- Add HTTPS server configuration example +- Lua Pages: mg.include should support absolute, relative and virtual path types +- Add API function for HTTP digest authentication +- Improved interface documentation +- Support parameters for Lua background scripts +- Use new connection queue implementation (previously ALTERNATIVE\_QUEUE) as default +- Add USE\_SERVER\_STATS define, so the server collects statistics data +- Convert system\_info text output and all other diagnostic strings to JSON format +- Add experimental function to query the connection status (may be dropped again) +- Add document on proposed future interface changes (for comments) +- Officially drop Symbian support +- Ignore leading blank lines in multipart messages (for Android upload service) +- Rewrite some functions, in particular request parsing +- CORS preflight directly in the server, with additional config options +- Solve some warnings from different static source code analysis tools +- Collect server status data +- Allow hostname in listening\_ports +- Make maximum request size configurable +- Allow multiple Sec-Websocket-Protocol +- Add configuration option to send additional headers +- Add configuration option for Strict-Transport-Security +- Mark "file in memory" feature is a candidate for deletion +- Improve examples +- Fix timeout error when sending larger files +- Add mg\_send\_chunk interface function +- Allow to separate server private key and certificate chain in two different files +- Support for multipart requests without quotes (for some C# clients) +- Initialize SSL in mg\_init\_library, so https client functions can be used when no server is running +- Allow "REPORT" HTTP method for REST calls to scripts +- Allow to compile civetweb.c wih a C++ compiler +- Lua: Remove internal length limits of encode/decode functions +- Allow sub-resources of index script files +- Add config parameter allow\_index\_script\_resource the aforementioned feature +- Remove deprecated "uri" member of the request from the interface +- Improve documentation +- Make auth domain check optional (configuration) +- Update unit test framework to check 0.11.0 (C89/C90 compilers still need a patched version) +- Limit depth of mg.include for Lua server pages +- Additional unit tests +- OpenSSL 1.1 support +- Update version number + + +Release Notes v1.9.1 +=== +### Objectives: *Bug fix* + +Changes +------- + +- Add "open website" button for pre-built Windows binaries +- Fix for connections closed prematurely +- Update to a new check unit test framework and remove patches required for previous version +- Update version number + + +Release Notes v1.9 +=== +### Objectives: *Read SSI client certificate information, improve windows usability, use non-blocking sockets, bug fixes* + +Changes +------- + +- Add library init/exit functions (call is now optional, but will be required in V1.10) +- Windows: Show system information from the tray icon +- Windows: Bring overlaid windows to top from the tray icon +- Add Lua background script, running independent from server state +- Move obsolete examples into separated directory +- Change name of CMake generated C++ library to civetweb-cpp +- Add option to set linger timeout +- Update Duktape and Lua (third-party code) +- Add continuous integration tests +- Add API documentation +- Limit recursions in .htpasswd files +- Fix SCRIPT_NAME for CGI directory index files (index.php) +- Use non-blocking sockets +- stdint.h is now required and no longer optional +- Rewrite connection close handling +- Rewrite mg_fopen/mg_stat +- Enhanced tray icon menu for Windows +- Add subprotocol management for websocket connections +- Partially rewrite timeout handling +- Add option keep_alive_timeout_ms +- Improve support for absolute URIs +- Allow some additional compiler checks (higher warning level) +- Add option for case sensitive file names for Windows +- Short notation for listening_ports option when using IPv4 and IPv6 ports +- Make usage of Linux sendfile configurable +- Optimize build matrix for Travis CI +- Retry failing TLS/HTTPS read/write operations +- Read client certificate information +- Do not tolerate URIs with invalid characters +- Fix mg_get_cookie to ignore substrings +- Fix memory leak in form handling +- Fix bug in timer logic (for Lua Websockets) +- Updated version number + Release Notes v1.8 === ### Objectives: *CMake integration and continuous integration tests, Support client certificates, bug fixes* @@ -285,6 +390,6 @@ Changes - Renamed Mongoose to Civetweb in the code and documentation. - Replaced copyrighted images with new images -- Created a new code respository at https://github.com/bel2125/civetweb +- Created a new code respository at https://github.com/civetweb/civetweb - Created a distribution site at https://sourceforge.net/projects/civetweb/ - Basic build testing diff --git a/ceph/src/civetweb/VisualStudio/civetweb.sln b/ceph/src/civetweb/VisualStudio/civetweb.sln index c6e488e6a..0e8672b99 100644 --- a/ceph/src/civetweb/VisualStudio/civetweb.sln +++ b/ceph/src/civetweb/VisualStudio/civetweb.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "civetweb_lua", "civetweb_lua\civetweb_lua.vcxproj", "{9BE9C008-E851-42B1-A034-BD4630AE4CD6}" ProjectSection(ProjectDependencies) = postProject @@ -28,8 +28,8 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|Win32.ActiveCfg = Debug|Win32 {9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|Win32.Build.0 = Debug|Win32 - {9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|x64.ActiveCfg = Release|x64 - {9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|x64.Build.0 = Release|x64 + {9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|x64.ActiveCfg = Debug|x64 + {9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|x64.Build.0 = Debug|x64 {9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Release|Win32.ActiveCfg = Release|Win32 {9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Release|Win32.Build.0 = Release|Win32 {9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Release|x64.ActiveCfg = Release|x64 diff --git a/ceph/src/civetweb/VisualStudio/civetweb_lua/civetweb_lua.vcxproj b/ceph/src/civetweb/VisualStudio/civetweb_lua/civetweb_lua.vcxproj index cd83d204e..45f8bbee9 100644 --- a/ceph/src/civetweb/VisualStudio/civetweb_lua/civetweb_lua.vcxproj +++ b/ceph/src/civetweb/VisualStudio/civetweb_lua/civetweb_lua.vcxproj @@ -22,13 +22,14 @@ {9BE9C008-E851-42B1-A034-BD4630AE4CD6} Win32Proj civetweb_lua + 8.1 Application true MultiByte - v140 + v140_xp Application @@ -47,7 +48,7 @@ false true MultiByte - v140 + v140_xp Application @@ -101,8 +102,8 @@ Level3 Disabled - USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.3.0\src;%(AdditionalIncludeDirectories) + USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.5.2\src;%(AdditionalIncludeDirectories) Windows @@ -115,8 +116,8 @@ Level3 Disabled - USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.3.0\src;%(AdditionalIncludeDirectories) + USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.5.2\src;%(AdditionalIncludeDirectories) Windows @@ -145,8 +146,8 @@ MaxSpeed true true - USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.3.0\src;%(AdditionalIncludeDirectories) + USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.5.2\src;%(AdditionalIncludeDirectories) Windows @@ -163,8 +164,8 @@ MaxSpeed true true - USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.3.0\src;%(AdditionalIncludeDirectories) + USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.5.2\src;%(AdditionalIncludeDirectories) Windows @@ -203,9 +204,11 @@ + + diff --git a/ceph/src/civetweb/VisualStudio/civetweb_lua/civetweb_lua.vcxproj.filters b/ceph/src/civetweb/VisualStudio/civetweb_lua/civetweb_lua.vcxproj.filters index ba5691da3..caf951c48 100644 --- a/ceph/src/civetweb/VisualStudio/civetweb_lua/civetweb_lua.vcxproj.filters +++ b/ceph/src/civetweb/VisualStudio/civetweb_lua/civetweb_lua.vcxproj.filters @@ -56,12 +56,18 @@ inl files + + inl files + inl files inl files + + inl files + inl files diff --git a/ceph/src/civetweb/VisualStudio/duktape_lib/duktape_lib.vcxproj b/ceph/src/civetweb/VisualStudio/duktape_lib/duktape_lib.vcxproj index ffc773d74..12fa214d2 100644 --- a/ceph/src/civetweb/VisualStudio/duktape_lib/duktape_lib.vcxproj +++ b/ceph/src/civetweb/VisualStudio/duktape_lib/duktape_lib.vcxproj @@ -29,7 +29,7 @@ StaticLibrary true MultiByte - v140 + v140_xp StaticLibrary @@ -42,7 +42,7 @@ false true MultiByte - v140 + v140_xp StaticLibrary @@ -144,11 +144,11 @@ - - + + - + diff --git a/ceph/src/civetweb/VisualStudio/duktape_lib/duktape_lib.vcxproj.filters b/ceph/src/civetweb/VisualStudio/duktape_lib/duktape_lib.vcxproj.filters index a5722d688..1aab8c811 100644 --- a/ceph/src/civetweb/VisualStudio/duktape_lib/duktape_lib.vcxproj.filters +++ b/ceph/src/civetweb/VisualStudio/duktape_lib/duktape_lib.vcxproj.filters @@ -15,15 +15,15 @@ - + Header Files - + Header Files - + Source Files diff --git a/ceph/src/civetweb/VisualStudio/ex_embed_cpp/ex_embed_cpp.vcxproj b/ceph/src/civetweb/VisualStudio/ex_embed_cpp/ex_embed_cpp.vcxproj index 3941edbff..a195fb698 100644 --- a/ceph/src/civetweb/VisualStudio/ex_embed_cpp/ex_embed_cpp.vcxproj +++ b/ceph/src/civetweb/VisualStudio/ex_embed_cpp/ex_embed_cpp.vcxproj @@ -28,7 +28,7 @@ Application true - v140 + v140_xp MultiByte @@ -40,7 +40,7 @@ Application false - v140 + v140_xp true MultiByte diff --git a/ceph/src/civetweb/VisualStudio/ex_embedded_c/ex_embedded_c.vcxproj b/ceph/src/civetweb/VisualStudio/ex_embedded_c/ex_embedded_c.vcxproj index fb81afff1..c3a429f14 100644 --- a/ceph/src/civetweb/VisualStudio/ex_embedded_c/ex_embedded_c.vcxproj +++ b/ceph/src/civetweb/VisualStudio/ex_embedded_c/ex_embedded_c.vcxproj @@ -35,7 +35,7 @@ Application true - v140 + v140_xp MultiByte @@ -47,7 +47,7 @@ Application false - v140 + v140_xp true MultiByte diff --git a/ceph/src/civetweb/VisualStudio/lua_lib/lua_lib.vcxproj b/ceph/src/civetweb/VisualStudio/lua_lib/lua_lib.vcxproj index 33d007fdd..a92e92ad8 100644 --- a/ceph/src/civetweb/VisualStudio/lua_lib/lua_lib.vcxproj +++ b/ceph/src/civetweb/VisualStudio/lua_lib/lua_lib.vcxproj @@ -29,7 +29,7 @@ StaticLibrary true MultiByte - v140 + v140_xp StaticLibrary @@ -42,7 +42,7 @@ false true MultiByte - v140 + v140_xp StaticLibrary diff --git a/ceph/src/civetweb/VisualStudio/unit_test/unit_test.vcxproj b/ceph/src/civetweb/VisualStudio/unit_test/unit_test.vcxproj index 76aa9b562..d3e02cd61 100644 --- a/ceph/src/civetweb/VisualStudio/unit_test/unit_test.vcxproj +++ b/ceph/src/civetweb/VisualStudio/unit_test/unit_test.vcxproj @@ -17,6 +17,7 @@ + @@ -25,26 +26,28 @@ + {1AC4A7A6-0100-4287-97F4-B95807BE5607} Win32Proj unit_test + 8.1 Application true MultiByte - v140 + v140_xp Application false true MultiByte - v140 + v140_xp @@ -70,7 +73,7 @@ Level3 Disabled - LOCAL_TEST;REPLACE_CHECK_FOR_LOCAL_DEBUGGING;USE_IPV6;USE_WEBSOCKET;MEMORY_DEBUGGING;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + REPLACE_CHECK_FOR_LOCAL_DEBUGGING;LOCAL_TEST;USE_IPV6;USE_WEBSOCKET;MEMORY_DEBUGGING;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) $(ProjectDir)..\..\src;$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\..\check-0.10.0\;$(ProjectDir)..\..\..\check-0.10.0\src\;%(AdditionalIncludeDirectories) @@ -86,7 +89,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + REPLACE_CHECK_FOR_LOCAL_DEBUGGING;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) $(ProjectDir)..\..\src;$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\..\check-0.10.0\;$(ProjectDir)..\..\..\check-0.10.0\src\;%(AdditionalIncludeDirectories) diff --git a/ceph/src/civetweb/VisualStudio/unit_test/unit_test.vcxproj.filters b/ceph/src/civetweb/VisualStudio/unit_test/unit_test.vcxproj.filters index 1e74b8bdf..bf33419b5 100644 --- a/ceph/src/civetweb/VisualStudio/unit_test/unit_test.vcxproj.filters +++ b/ceph/src/civetweb/VisualStudio/unit_test/unit_test.vcxproj.filters @@ -30,12 +30,18 @@ Headerdateien + + Headerdateien + Headerdateien Headerdateien + + Quelldateien + diff --git a/ceph/src/civetweb/_config.yml b/ceph/src/civetweb/_config.yml new file mode 100644 index 000000000..259a24e4d --- /dev/null +++ b/ceph/src/civetweb/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-tactile \ No newline at end of file diff --git a/ceph/src/civetweb/appveyor.yml b/ceph/src/civetweb/appveyor.yml index 793147c68..87455a2bb 100644 --- a/ceph/src/civetweb/appveyor.yml +++ b/ceph/src/civetweb/appveyor.yml @@ -1,11 +1,18 @@ version: '{build}' -configuration: - - Release -platform: - - x86 - - x64 +build: +# no automatic build in script mode + + +skip_commits: + # Builds just testing something on Travis CI don't need to be + # done on AppVeyor + message: /\[Travis\]/ + # Dont build, if only documentation was changed + files: + - '**/*.md' + environment: enable_cxx: NO @@ -15,70 +22,206 @@ environment: c_standard: auto cxx_standard: auto matrix: - - compiler: msvc-18-seh + # Use default values + - id: Default-x86 + compiler: msvc-19-seh build_shared: NO no_files: NO enable_ipv6: NO enable_ssl: YES - enable_websockets: YES - no_cgi: NO - no_caching: NO - - compiler: msvc-18-seh - build_shared: YES - no_files: NO - enable_ipv6: NO - enable_ssl: YES - enable_websockets: YES - no_cgi: NO - no_caching: NO - - compiler: msvc-18-seh - build_shared: YES - no_files: YES - enable_ipv6: NO - enable_ssl: YES - enable_websockets: YES - no_cgi: NO - no_caching: NO - - compiler: gcc-5.1.0-posix - build_shared: NO - no_files: YES - enable_ipv6: NO - enable_ssl: NO enable_websockets: NO - no_cgi: YES - no_caching: YES - - compiler: gcc-5.1.0-posix + no_cgi: NO + no_caching: NO + configuration: Release + platform: x86 + - id: Default-x64 + compiler: msvc-19-seh + build_shared: NO + no_files: NO + enable_ipv6: NO + enable_ssl: YES + enable_websockets: NO + no_cgi: NO + no_caching: NO + configuration: Release + platform: x64 + # Use default values + - id: Full-x86 + compiler: msvc-19-seh build_shared: NO no_files: NO enable_ipv6: YES enable_ssl: YES enable_websockets: YES no_cgi: NO - no_caching: YES - - compiler: gcc-5.1.0-posix + no_caching: NO + configuration: Release + platform: x86 + - id: Full-x64 + compiler: msvc-19-seh build_shared: NO no_files: NO - enable_ipv6: NO + enable_ipv6: YES enable_ssl: YES enable_websockets: YES no_cgi: NO - no_caching: YES - - compiler: gcc-5.1.0-posix + no_caching: NO + configuration: Release + platform: x64 + # Debug builds + - id: Full-x86-Debug + compiler: msvc-19-seh + build_shared: NO + no_files: NO + enable_ipv6: YES + enable_ssl: YES + enable_websockets: YES + no_cgi: NO + no_caching: NO + configuration: Debug + platform: x86 + - id: Full-x64-Debug + compiler: msvc-19-seh + build_shared: NO + no_files: NO + enable_ipv6: YES + enable_ssl: YES + enable_websockets: YES + no_cgi: NO + no_caching: NO + configuration: Debug + platform: x64 + # Minimum settings + - id: Minimal-x86 + compiler: msvc-19-seh + build_shared: NO + no_files: YES + enable_ipv6: NO + enable_ssl: NO + enable_websockets: NO + no_cgi: YES + no_caching: YeS + configuration: Release + platform: x86 + - id: Minimal-x64 + compiler: msvc-19-seh + build_shared: NO + no_files: YES + enable_ipv6: NO + enable_ssl: NO + enable_websockets: NO + no_cgi: YES + no_caching: YeS + configuration: Release + platform: x64 + # Test shared and debug build + - id: Shared-default-x86 + compiler: msvc-19-seh build_shared: YES no_files: NO enable_ipv6: NO enable_ssl: YES - enable_websockets: YES + enable_websockets: NO no_cgi: NO - no_caching: YES - - compiler: gcc-5.1.0-posix + no_caching: NO + configuration: Release + platform: x86 + - id: Shared-default-x64 + compiler: msvc-19-seh build_shared: YES - no_files: YES + no_files: NO enable_ipv6: NO enable_ssl: YES + enable_websockets: NO + no_cgi: NO + no_caching: NO + configuration: Release + platform: x64 + # MinGW + - id: Full-GCC-x64 + compiler: gcc-5.1.0-posix + build_shared: NO + no_files: NO + enable_ipv6: YES + enable_ssl: YES enable_websockets: YES no_cgi: NO - no_caching: YES + no_caching: NO + configuration: Release + platform: x64 + # Visual Studio 2010 + - id: Full-VS2010-x86 + compiler: msvc-16-seh + build_shared: NO + no_files: NO + enable_ipv6: YES + enable_ssl: YES + enable_websockets: YES + no_cgi: NO + no_caching: NO + configuration: Release + platform: x86 + # Visual Studio 2012 + - id: Full-VS2012-x86 + compiler: msvc-17-seh + build_shared: NO + no_files: NO + enable_ipv6: YES + enable_ssl: YES + enable_websockets: YES + no_cgi: NO + no_caching: NO + configuration: Release + platform: x86 + # Visual Studio 2013 + - id: Full-VS2013-x86 + compiler: msvc-18-seh + build_shared: NO + no_files: NO + enable_ipv6: YES + enable_ssl: YES + enable_websockets: YES + no_cgi: NO + no_caching: NO + configuration: Release + platform: x86 + - id: Full-VS2013-x64 + compiler: msvc-18-seh + build_shared: NO + no_files: NO + enable_ipv6: YES + enable_ssl: YES + enable_websockets: YES + no_cgi: NO + no_caching: NO + configuration: Release + platform: x64 + # Visual Studio 2015 is default + # Visual Studio 2017 is not yet default + - id: Full-VS2017-x86 + compiler: msvc-20-seh + build_shared: NO + no_files: NO + enable_ipv6: YES + enable_ssl: YES + enable_websockets: YES + no_cgi: NO + no_caching: NO + configuration: Release + platform: x86 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + - id: Full-VS2017-x64 + compiler: msvc-20-seh + build_shared: NO + no_files: NO + enable_ipv6: YES + enable_ssl: YES + enable_websockets: YES + no_cgi: NO + no_caching: NO + configuration: Release + platform: x64 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 install: @@ -138,6 +281,7 @@ before_build: - if "%compiler_version%"=="17" (set "vs_version=11" & set "vs_year=2012") - if "%compiler_version%"=="18" (set "vs_version=12" & set "vs_year=2013") - if "%compiler_version%"=="19" (set "vs_version=14" & set "vs_year=2015") + - if "%compiler_version%"=="20" (set "vs_version=15" & set "vs_year=2017") - if "%compiler_name%"=="msvc" (set "generator=Visual Studio %vs_version% %vs_year%") - if "%compiler_name%"=="msvc" ( if "%platform%"=="x64" ( @@ -203,12 +347,30 @@ test_script: - cmd /c "%test%" - cd "%source_path%" + - set "output_path=%source_path%\output" + - set "build_path=%output_path%\build" + - set "install_path=%output_path%\install" + - set "third_party_dir=C:\third-party" + after_test: + - echo "Current directory:" - cd - dir - md dist - - cmake "-DCMAKE_INSTALL_PREFIX=%install_path%" -P "%build_path%/cmake_install.cmake" - - copy "%build_path%" dist\ + - if "%build_type%"=="Release" (cmake "-DCMAKE_INSTALL_PREFIX=%install_path%" -P "%build_path%/cmake_install.cmake") + - dir dist\ + - echo "Output directory:" + - dir %output_path% + - echo "Build directory:" + - dir %build_path% + - if "%build_type%"=="Release" (echo "Install directory:") + - if "%build_type%"=="Release" (dir %install_path%) + - if "%build_type%"=="Release" (dir %install_path%\bin) + - if "%build_type%"=="Release" (dir %install_path%\include) + - if "%build_type%"=="Release" (dir %install_path%\lib) + - if "%build_type%"=="Release" (copy "%install_path%"\include dist\) + - if "%build_type%"=="Release" (copy "%install_path%"\bin\*.exe dist\) + - echo "Dist directory:" - dir dist\ matrix: diff --git a/ceph/src/civetweb/ci/travis/install_rocks.sh b/ceph/src/civetweb/ci/travis/install_rocks.sh index 26e6f3600..739248b84 100755 --- a/ceph/src/civetweb/ci/travis/install_rocks.sh +++ b/ceph/src/civetweb/ci/travis/install_rocks.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -ev source ci/travis/lua_env.sh diff --git a/ceph/src/civetweb/ci/travis/lua_env.sh b/ceph/src/civetweb/ci/travis/lua_env.sh index 3bb189381..dd742e911 100755 --- a/ceph/src/civetweb/ci/travis/lua_env.sh +++ b/ceph/src/civetweb/ci/travis/lua_env.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash LUAROCKS=ci/lua/bin/luarocks eval $($LUAROCKS path --bin) diff --git a/ceph/src/civetweb/ci/travis/run_ci_tests.sh b/ceph/src/civetweb/ci/travis/run_ci_tests.sh index 33c55dde9..16c2cc067 100755 --- a/ceph/src/civetweb/ci/travis/run_ci_tests.sh +++ b/ceph/src/civetweb/ci/travis/run_ci_tests.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -ev source ci/travis/lua_env.sh diff --git a/ceph/src/civetweb/ci/travis/setup_lua.sh b/ceph/src/civetweb/ci/travis/setup_lua.sh index 0992a89b4..8e1b324ea 100755 --- a/ceph/src/civetweb/ci/travis/setup_lua.sh +++ b/ceph/src/civetweb/ci/travis/setup_lua.sh @@ -1,4 +1,4 @@ -#! /bin/bash +#!/usr/bin/env /bash set -ev # this script installs a lua / luarocks environment in .travis/lua diff --git a/ceph/src/civetweb/cmake/FindLibM.cmake b/ceph/src/civetweb/cmake/FindLibM.cmake index 0b2053d94..9f42aa493 100644 --- a/ceph/src/civetweb/cmake/FindLibM.cmake +++ b/ceph/src/civetweb/cmake/FindLibM.cmake @@ -29,7 +29,8 @@ find_path(LIBM_INCLUDE_DIRS NAMES math.h - PATHS ${LIBM_ROOT}/include/ + PATHS /usr/include /usr/local/include /usr/local/bic/include + NO_DEFAULT_PATH ) find_library(LIBM_LIBRARIES m) include(FindPackageHandleStandardArgs) diff --git a/ceph/src/civetweb/contrib/buildroot/civetweb.mk b/ceph/src/civetweb/contrib/buildroot/civetweb.mk index e37f9ee83..8b9b7de0b 100644 --- a/ceph/src/civetweb/contrib/buildroot/civetweb.mk +++ b/ceph/src/civetweb/contrib/buildroot/civetweb.mk @@ -4,7 +4,7 @@ # ################################################################################ -CIVETWEB_VERSION = 1.8 +CIVETWEB_VERSION = 1.10 CIVETWEB_SITE = http://github.com/civetweb/civetweb/tarball/v$(CIVETWEB_VERSION) CIVETWEB_LICENSE = MIT CIVETWEB_LICENSE_FILES = LICENSE.md diff --git a/ceph/src/civetweb/docs/APIReference.md b/ceph/src/civetweb/docs/APIReference.md new file mode 100644 index 000000000..58c2faf38 --- /dev/null +++ b/ceph/src/civetweb/docs/APIReference.md @@ -0,0 +1,134 @@ +# CivetWeb API Reference + +CivetWeb is often used as HTTP and HTTPS library inside a larger application. +A C API is available to integrate the CivetWeb functionality in a larger +codebase. A C++ wrapper is also available, although it is not guaranteed +that all functionality available through the C API can also be accessed +from C++. This document describes the public C API. Basic usage examples of +the API can be found in [Embedding.md](Embedding.md), as well as in the +examples directory. + +## Macros + +| Macro | Description | +| :--- | :--- | +| **`CIVETWEB_VERSION`** | The current version of the software as a string with the major and minor version number seperated with a dot. For version 1.9, this string will have the value "1.9", for thw first patch of this version "1.9.1". | +| **`CIVETWEB_VERSION_MAJOR`** | The current major version as number, e.g., (1) for version 1.9. | +| **`CIVETWEB_VERSION_MINOR`** | The current minor version as number, e.g., (9) for version 1.9. | +| **`CIVETWEB_VERSION_PATCH`** | The current patch version as number, e.g., (0) for version 1.9 or (1) for version 1.9.1. | + +## Handles + +* `struct mg_context *` +Handle for one instance of the HTTP(S) server. +All functions using `const struct mg_context *` as an argument do not modify a running server instance, but just query information. Functions using a non-const `struct mg_context *` as an argument may modify a server instance (e.g., register a new URI, stop the server, ...). + +* `struct mg_connection *` +Handle for one individual client-server connection. +Functions working with `const struct mg_connection *` operate on data already known to the server without reading data from or sending data to the client. Callbacks using a `const struct mg_connection *` argument are supposed to not call functions from the `mg_read()` and `mg_write()` family. To support a correct application, reading and writing functions require a non-const `struct mg_connection *` connection handle. + +The content of both structures is not defined in the interface - they are only used as opaque pointers (handles). + +## Structures + +* [`struct mg_client_cert;`](api/mg_client_cert.md) +* [`struct mg_client_options;`](api/mg_client_options.md) +* [`struct mg_callbacks;`](api/mg_callbacks.md) +* [`struct mg_form_data_handler;`](api/mg_form_data_handler.md) +* [`struct mg_header;`](api/mg_header.md) +* [`struct mg_option;`](api/mg_option.md) +* [`struct mg_request_info;`](api/mg_request_info.md) +* [`struct mg_server_ports;`](api/mg_server_ports.md) + + +## Library API Functions + +* [`mg_init_library( feature );`](api/mg_init_library.md) +* [`mg_exit_library( feature );`](api/mg_exit_library.md) + +* [`mg_check_feature( feature );`](api/mg_check_feature.md) +* [`mg_version();`](api/mg_version.md) + + +## Server API Functions + +* [`mg_start( callbacks, user_data, options );`](api/mg_start.md) +* [`mg_stop( ctx );`](api/mg_stop.md) + +* [`mg_get_builtin_mime_type( file_name );`](api/mg_get_builtin_mime_type.md) +* [`mg_get_option( ctx, name );`](api/mg_get_option.md) +* [`mg_get_server_ports( ctx, size, ports );`](api/mg_get_server_ports.md) +* [`mg_get_user_data( ctx );`](api/mg_get_user_data.md) +* [`mg_set_auth_handler( ctx, uri, handler, cbdata );`](api/mg_set_auth_handler.md) +* [`mg_set_request_handler( ctx, uri, handler, cbdata );`](api/mg_set_request_handler.md) +* [`mg_set_websocket_handler( ctx, uri, connect_handler, ready_handler, data_handler, close_handler, cbdata );`](api/mg_set_websocket_handler.md) + +* [`mg_lock_context( ctx );`](api/mg_lock_context.md) +* [`mg_unlock_context( ctx );`](api/mg_unlock_context.md) + +* [`mg_get_context( conn );`](api/mg_get_context.md) + +* [`mg_send_http_error( conn, status_code, fmt, ... );`](api/mg_send_http_error.md) + +* [`mg_send_digest_access_authentication_request( conn, realm );`](api/mg_send_digest_access_authentication_request.md) +* [`mg_check_digest_access_authentication( conn, realm, filename );`](api/mg_check_digest_access_authentication.md) +* [`mg_modify_passwords_file( passwords_file_name, realm, user, password );`](api/mg_modify_passwords_file.md) + + +## Client API Functions + +* [`mg_connect_client( host, port, use_ssl, error_buffer, error_buffer_size );`](api/mg_connect_client.md) +* [`mg_connect_websocket_client( host, port, use_ssl, error_buffer, error_buffer_size, path, origin, data_func, close_func, user_data);`](api/mg_connect_websocket_client.md) +* [`mg_websocket_client_write( conn, opcode, data, data_len );`](api/mg_websocket_client_write.md) + +* [`mg_download( host, port, use_ssl, error_buffer, error_buffer_size, fmt, ... );`](api/mg_download.md) + + +## Common API Functions + +* [`mg_close_connection( conn );`](api/mg_close_connection.md) +* [`mg_cry( conn, fmt, ... );`](api/mg_cry.md) + +* [`mg_get_cookie( cookie, var_name, buf, buf_len );`](api/mg_get_cookie.md) +* [`mg_get_header( conn, name );`](api/mg_get_header.md) +* [`mg_get_request_info( conn );`](api/mg_get_request_info.md) +* [`mg_get_response( conn, ebuf, ebuf_len, timeout );`](api/mg_get_response.md) +* [`mg_get_response_code_text( conn, response_code );`](api/mg_get_response_code_text.md) +* [`mg_get_user_connection_data( conn );`](api/mg_get_user_connection_data.md) +* [`mg_get_valid_options();`](api/mg_get_valid_options.md) +* [`mg_get_var( data, data_len, var_name, dst, dst_len );`](api/mg_get_var.md) +* [`mg_get_var2( data, data_len, var_name, dst, dst_len, occurrence );`](api/mg_get_var2.md) +* [`mg_handle_form_request( conn, fdh );`](api/mg_handle_form_request.md) +* [`mg_lock_connection( conn );`](api/mg_lock_connection.md) +* [`mg_md5( buf, ... );`](api/mg_md5.md) +* [`mg_printf( conn, fmt, ... );`](api/mg_printf.md) +* [`mg_read( conn, buf, len );`](api/mg_read.md) +* [`mg_send_chunk( conn, buf, len );`](api/mg_send_chunk.md) +* [`mg_send_file( conn, path );`](api/mg_send_file.md) +* [`mg_send_mime_file( conn, path, mime_type );`](api/mg_send_mime_file.md) +* [`mg_send_mime_file2( conn, path, mime_type, additional_headers );`](api/mg_send_mime_file2.md) +* [`mg_set_user_connection_data( conn, data );`](api/mg_set_user_connection_data.md) +* [`mg_start_thread( f, p );`](api/mg_start_thread.md) +* [`mg_store_body( conn, path );`](api/mg_store_body.md) +* [`mg_strcasecmp( s1, s2 );`](api/mg_strcasecmp.md) +* [`mg_strncasecmp( s1, s2, len );`](api/mg_strncasecmp.md) +* [`mg_unlock_connection( conn );`](api/mg_unlock_connection.md) +* [`mg_url_decode( src, src_len, dst, dst_len, is_form_url_encoded );`](api/mg_url_decode.md) +* [`mg_url_encode( src, dst, dst_len );`](api/mg_url_encode.md) +* [`mg_websocket_write( conn, opcode, data, data_len );`](api/mg_websocket_write.md) +* [`mg_write( conn, buf, len );`](api/mg_write.md) + + +## Diagnosis Functions + +* [`mg_get_system_info( buffer, buf_len );`](api/mg_get_system_info.md) +* [`mg_get_context_info( ctx, buffer, buf_len );`](api/mg_get_context_info.md) +* [`mg_get_connection_info( ctx, idx, buffer, buf_len );`](api/mg_get_context_info.md) + + +## Deprecated: + +* [~~`mg_get_valid_option_names();`~~](api/mg_get_valid_option_names.md) +* [~~`mg_upload( conn, destination_dir );`~~](api/mg_upload.md) + + diff --git a/ceph/src/civetweb/docs/Building.md b/ceph/src/civetweb/docs/Building.md index 9668f61b2..9d7b56ff7 100644 --- a/ceph/src/civetweb/docs/Building.md +++ b/ceph/src/civetweb/docs/Building.md @@ -82,27 +82,56 @@ make build WITH_LUA=1 ``` -| Make Options | Description | -| ------------------------- | ---------------------------------------- | -| WITH_LUA=1 | build with Lua support | -| WITH_DEBUG=1 | build with GDB debug support | -| WITH_IPV6=1 | with IPV6 support | -| WITH_WEBSOCKET=1 | build with web socket support | -| WITH_CPP=1 | build libraries with c++ classes | -| CONFIG_FILE=file | use 'file' as the config file | -| CONFIG_FILE2=file | use 'file' as the backup config file | -| HTMLDIR=/path | place to install initial web pages | -| DOCUMENT_ROOT=/path | HTMLDIR override, config option, install | -| | nothing is installed here. | -| PORTS=8080 | listening ports override when installing | -| SSL_LIB=libssl.so.0 | use versioned SSL library | -| CRYPTO_LIB=libcrypto.so.0 | system versioned CRYPTO library | -| PREFIX=/usr/local | sets the install directory | -| COPT='-DNO_SSL' | method to insert compile flags | +| Make Options | Description | +| ------------------------- | ----------------------------------------- | +| WITH_LUA=1 | build with Lua support | +| WITH_DUKTAPE=1 | build with server-side JavaScript support | +| WITH_DEBUG=1 | build with GDB debug support | +| WITH_IPV6=1 | with IPV6 support | +| WITH_WEBSOCKET=1 | build with web socket support | +| WITH_SERVER_STATS=1 | build with support for server statistics | +| WITH_CPP=1 | build libraries with c++ classes | +| CONFIG_FILE=file | use 'file' as the config file | +| CONFIG_FILE2=file | use 'file' as the backup config file | +| HTMLDIR=/path | place to install initial web pages | +| DOCUMENT_ROOT=/path | HTMLDIR override, config option, install | +| | nothing is installed here. | +| PORTS=8080 | listening ports override when installing | +| SSL_LIB=libssl.so.0 | use versioned SSL library | +| CRYPTO_LIB=libcrypto.so.0 | system versioned CRYPTO library | +| PREFIX=/usr/local | sets the install directory | +| COPT='-DNO_SSL' | method to insert compile flags | Note that the WITH_* options used for *make* are not identical to the preprocessor defines in the source code - usually USE_* is used there. +## Changing PREFIX + +To change the target destination pass the `PREFIX` option to the command `make install` (not `make build`). Example usage: + +``` +$ make build +$ make -n install PREFIX=/opt/civetweb +``` +Note: The `-n` corresponds to the `--dry-run` option (it does not make any changes): You can see where `make install` would install. Example output of the above command: + +``` +$ make -n install PREFIX=/opt/civetweb +install -d -m 755 "/opt/civetweb/share/doc/civetweb" +install -m 644 resources/itworks.html /opt/civetweb/share/doc/civetweb/index.html +install -m 644 resources/civetweb_64x64.png /opt/civetweb/share/doc/civetweb/ +install -d -m 755 "/opt/civetweb/etc" +install -m 644 resources/civetweb.conf "/opt/civetweb/etc/" +sed -i 's#^document_root.*$#document_root /opt/civetweb/share/doc/civetweb#' "/opt/civetweb/etc/civetweb.conf" +sed -i 's#^listening_ports.*$#listening_ports 8080#' "/opt/civetweb/etc/civetweb.conf" +install -d -m 755 "/opt/civetweb/share/doc/civetweb" +install -m 644 *.md "/opt/civetweb/share/doc/civetweb" +install -d -m 755 "/opt/civetweb/bin" +install -m 755 civetweb "/opt/civetweb/bin/" +``` + +If the output looks good: Just remove the `-n` option to actually install the software on your system. + ## Setting compile flags Compile flags can be set using the *COPT* make option like so. @@ -162,9 +191,8 @@ Building with Buildroot Building on Android --------- -This is a small guide to help you run civetweb on Android. Currently it is -tested on the HTC Wildfire. If you have managed to run it on other devices -as well, please comment or drop an email in the mailing list. +This is a small guide to help you run civetweb on Android, originally +tested on the HTC Wildfire. Note: You do not need root access to run civetweb on Android. - Download the source from the Downloads page. @@ -177,15 +205,12 @@ Note: You do not need root access to run civetweb on Android. - To test if the server is running fine, visit your web-browser and navigate to `http://127.0.0.1:8080` You should see the `Index of /` page. -![screenshot](https://a248.e.akamai.net/camo.github.com/b88428bf009a2b6141000937ab684e04cc8586af/687474703a2f2f692e696d6775722e636f6d2f62676f6b702e706e67) - Notes: - `jni` stands for Java Native Interface. Read up on Android NDK if you want to know how to interact with the native C functions of civetweb in Android Java applications. -- TODO: A Java application that interacts with the native binary or a - shared library. + diff --git a/ceph/src/civetweb/docs/Contribution.md b/ceph/src/civetweb/docs/Contribution.md index de3ff4378..aa88c14ff 100644 --- a/ceph/src/civetweb/docs/Contribution.md +++ b/ceph/src/civetweb/docs/Contribution.md @@ -3,8 +3,21 @@ Contributing to CivetWeb Contributions to CivetWeb are welcome, provided all contributions carry the MIT license. -- Please first create an issue on GitHub or create a thread on the CivetWeb discussion group. -- If possible, create a pull request on GitHub. Please take care your modifications pass the continuous integration checks. These checks are performed automatically when you create a pull request, but it may take some hours until all tests are completed. -- Alternatively, you can post a patch. However, pull requests are preferred. -- Contributor names are listed in CREDITS.md, unless you explicitly state you don't want your name to be listed there. +- Please report issues on GitHub. If the issue you want to report is already reported there, add a note with your specific details to that issue. In case of doubt, please create a new issue. +- If you know how to fix the issue, please create a pull request on GitHub. Please take care your modifications pass the continuous integration checks. These checks are performed automatically when you create a pull request, but it may take some hours until all tests are completed. Please provide a description for every pull request. +- Alternatively, you can post a patch or describe the required modifications in a GitHub issue. +However, a pull request would be preferred. +- Contributor names are listed in CREDITS.md, unless you explicitly state you don't want your name to be listed there. This file is occasionally updated, adding new contributors, using author names from git commits and GitHub comments. + + +- In case your modifications either + 1. modify or extend the API, + 2. affect multi-threading, + 3. imply structural changes, + or + 4. have significant influence on maintenance, + + please first create an issue on GitHub or create a thread on the CivetWeb discussion group, to discuss the planned changed. + +- In case you think you found a security issue that should be evaluated and fixed before public disclosure, feel free to write an email. Although CivetWeb is a fork from Mongoose from 2013, the code bases are different now, so security vulnerabilities of Mongoose usually do not affect CivetWeb. Open an issue for Mongoose vulnerabilities you want to have checked if CivetWeb is affected. diff --git a/ceph/src/civetweb/docs/Embedding.md b/ceph/src/civetweb/docs/Embedding.md index 3f2a2db97..0ffbc230d 100644 --- a/ceph/src/civetweb/docs/Embedding.md +++ b/ceph/src/civetweb/docs/Embedding.md @@ -24,15 +24,19 @@ but all functions required to run a HTTP server. - C implementation - src/civetweb.c - src/md5.inl (MD5 calculation) - - src/handle_form.inl (HTML form handling functions) + - src/sha1.inl (SHA calculation) + - src/handle\_form.inl (HTML form handling functions) + - src/timer.inl (optional timer support) - Optional: C++ wrapper - include/CivetServer.h (C++ interface) - src/CivetServer.cpp (C++ wrapper implementation) - Optional: Third party components - - src/third_party/* (third party components, mainly used for the standalone server) - - src/mod_*.inl (modules to access third party components from civetweb) + - src/third\_party/* (third party components, mainly used for the standalone server) + - src/mod\_*.inl (modules to access third party components from civetweb) + + +Note: The C++ wrapper uses the official C interface (civetweb.h) and does not add new features to the server. Several features available in the C interface are missing in the C++ interface. While all features should be accessible using the C interface, this is not a design goal of the C++ interface. -Note: The C++ wrapper uses the official C interface (civetweb.h) and does not add new features to the server. Some features available in the C interface might be missing in the C++ interface. #### Additional Source Files for Executables @@ -42,12 +46,13 @@ starting the HTTP server. - Stand-alone C Server - src/main.c - Reference embedded C Server - - examples/embedded_c/embedded_c.c + - examples/embedded\_c/embedded\_c.c - Reference embedded C++ Server - - examples/embedded_cpp/embedded_cpp.cpp + - examples/embedded\_cpp/embedded\_cpp.cpp Note: The "embedded" example is actively maintained, updated, extended and tested. Other examples in the examples/ folder might be outdated and remain there for reference. + Quick Start ------ @@ -70,6 +75,9 @@ By default, the server will automatically serve up files like a normal HTTP serv - Use contructor *options* to select the port and document root among other things. - Use constructor *callbacks* to add your own hooks. +Alternative quick start: Have a look at the examples embedded\_c and embedded\_cpp + + Lua Support ------ @@ -77,15 +85,15 @@ Lua is a server side include functionality. Files ending in .lua will be proces ##### Add the following CFLAGS - - -DLUA_COMPAT_ALL - - -DUSE_LUA - - -DUSE_LUA_SQLITE3 - - -DUSE_LUA_FILE_SYSTEM + - `-DLUA_COMPAT_ALL` + - `-DUSE_LUA` + - `-DUSE_LUA_SQLITE3` + - `-DUSE_LUA_FILE_SYSTEM` ##### Add the following sources - - src/mod_lua.inl - - src/third_party/lua-5.2.4/src + - src/mod\_lua.inl + - src/third\_party/lua-5.2.4/src + lapi.c + lauxlib.c + lbaselib.c @@ -118,11 +126,11 @@ Lua is a server side include functionality. Files ending in .lua will be proces + lundump.c + lvm.c + lzio.c - - src/third_party/sqlite3.c - - src/third_party/sqlite3.h - - src/third_party/lsqlite3.c - - src/third_party/lfs.c - - src/third_party/lfs.h + - src/third\_party/sqlite3.c + - src/third\_party/sqlite3.h + - src/third\_party/lsqlite3.c + - src/third\_party/lfs.c + - src/third\_party/lfs.h This build is valid for Lua version Lua 5.2. It is also possible to build with Lua 5.1 (including LuaJIT) or Lua 5.3. @@ -156,8 +164,8 @@ is configurable via `num_threads` configuration option. That number puts a limit on number of simultaneous requests that can be handled by CivetWeb. If you embed CivetWeb into a program that uses SSL outside CivetWeb as well, you may need to initialize SSL before calling `mg_start()`, and set the pre- -processor define SSL_ALREADY_INITIALIZED. This is not required if SSL is used -only within CivetWeb. +processor define `SSL_ALREADY_INITIALIZED`. This is not required if SSL is +used only within CivetWeb. When master thread accepts new a connection, a new accepted socket (described by `struct socket`) it placed into the accepted sockets queue, @@ -174,11 +182,13 @@ which is `SOMAXCONN` and depends on the platform. Worker threads are running in an infinite loop, which in a simplified form looks something like this: +```C static void *worker_thread() { while (consume_socket()) { process_new_connection(); } } +``` Function `consume_socket()` gets a new accepted socket from the CivetWeb socket queue, atomically removing it from the queue. If the queue is empty, @@ -198,3 +208,53 @@ All accepted sockets have `SO_RCVTIMEO` and `SO_SNDTIMEO` socket options set (controlled by the `request_timeout_ms` CivetWeb option, 30 seconds default) which specifies a read/write timeout on client connections. + +A minimal example +------ + +Initializing a HTTP server +```C +{ + /* Server context handle */ + struct mg_context *ctx; + + /* Initialize the library */ + mg_init_library(0); + + /* Start the server */ + ctx = mg_start(NULL, 0, NULL); + + /* Add some handler */ + mg_set_request_handler(ctx, "/hello", handler, "Hello world"); + + ... Run the application ... + + /* Stop the server */ + mg_stop(ctx); + + /* Un-initialize the library */ + mg_exit_library(); +} +``` + +A simple callback +```C +static int +handler(struct mg_connection *conn, void *ignored) +{ + const char *msg = "Hello world"; + unsigned long len = (unsigned long)strlen(msg); + + mg_printf(conn, + "HTTP/1.1 200 OK\r\n" + "Content-Length: %lu\r\n" + "Content-Type: text/plain\r\n" + "Connection: close\r\n\r\n", + len); + + mg_write(conn, msg, len); + + return 200; +} +``` + diff --git a/ceph/src/civetweb/docs/Installing.md b/ceph/src/civetweb/docs/Installing.md index d5e87cc97..2476b94fd 100644 --- a/ceph/src/civetweb/docs/Installing.md +++ b/ceph/src/civetweb/docs/Installing.md @@ -10,8 +10,10 @@ This pre-built version comes pre-built wit Lua support. Libraries for SSL suppor however, users may add an SSL library themselves. Instructions for adding SSL support can be found in [https://github.com/civetweb/civetweb/tree/master/docs](https://github.com/civetweb/civetweb/tree/master/docs) -1a. 32 Bit: Install the [Visual C++ Redistributable for Visual Studio 2010](http://www.microsoft.com/en-us/download/details.aspx?id=8328) -1b. 64 Bit: Install the [Visual C++ Redistributable for Visual Studio 2013](http://www.microsoft.com/en-us/download/details.aspx?id=40784) +1. In case the Visual C++ Redistributable are not already installed: + 32 Bit Version: Install the [Redistributable for Visual Studio 2010](http://www.microsoft.com/en-us/download/details.aspx?id=8328) + 64 Bit Version: Install the [Redistributable for Visual Studio 2015](http://www.microsoft.com/en-us/download/details.aspx?id=48145) + Note: The required version of the Redistributables may vary, depending on the CivetWeb version. 2. Download latest *civetweb-win.zip* from [SourceForge](https://sourceforge.net/projects/civetweb/files/) 3. When started, Civetweb puts itself into the tray. diff --git a/ceph/src/civetweb/docs/Interface_Changes_1.10.md b/ceph/src/civetweb/docs/Interface_Changes_1.10.md new file mode 100644 index 000000000..16bc7dde5 --- /dev/null +++ b/ceph/src/civetweb/docs/Interface_Changes_1.10.md @@ -0,0 +1,86 @@ +# Interface changes + +## Proposed interface changes for 1.10 + +Status: To be discussed + +### Server interface + +#### mg\_start / mg\_init\_library + +Calling mg\_init\_library is recommended before calling mg\_start. + +Compatibility: +Initially, mg\_init\_library will be called implicitly if it has +not been called before mg\_start. +If mg\_init\_library was not called, mg\_stop may leave memory leaks. + +#### mg\_websocket\_write functions + +Calling mg\_lock\_connection is no longer called implicitly +in mg\_websocket\_write functions. +If you use websocket write functions them from two threads, +you must call mg\_lock\_connection explicitly, just like for any +other connection. + +This is an API harmonization issue. + +Compatibility: +If a websocket connection was used in only one thread, there is +no incompatibility. If a websocket connection was used in multiple +threads, the user has to add the mg\_lock\_connection before and +the mg\_unlock\_connection after the websocket write call. + +#### open\_file member of mg\_callbacks + +This member is going to be removed. +It is superseeded by mg\_add\_request\_handler. + +Compatibility: +Current code using open\_file needs to be changed. +Instructions how to do this will be provided. + + +### Client interface + + +#### mg\_init\_library + +Calling mg\_init\_library is required before calling any client +function. In particular, the TLS initialization must be done +before using mg\_connect\_client\_secure. + +Compatibility: +Some parts of the client interface did not work, if mg\_start +was not called before. Now server and client become independent. + +#### mg\_connect\_client (family) + +mg_connect_client needs several new parameters (options). + +Details are to be defined. + +mg_connect_client and mg_download should return a different kind of +mg_connection than used in server callbacks. At least, there should +be a function mg_get_response_info, instead of using +mg_get_request_info, and getting the HTTP response code from the +server by looking into the uri member of struct mg_request_info. + + +### `size_t` in all interface + +Having `size_t` in interfaces while building for 32 and 64 bit +complicates maintenance in an unnecessary way +(see [498](https://github.com/civetweb/civetweb/issues/498)). + +Replace all data sizes by 64 bit integers. + + +### Pattern definition + +The current definition of pattern matching is problematic +(see [499](https://github.com/civetweb/civetweb/issues/499)). + +Find and implement a new definition. + + diff --git a/ceph/src/civetweb/docs/README.md b/ceph/src/civetweb/docs/README.md new file mode 100644 index 000000000..9494409f9 --- /dev/null +++ b/ceph/src/civetweb/docs/README.md @@ -0,0 +1,42 @@ +![CivetWeb](https://raw.github.com/civetweb/civetweb/master/resources/civetweb_64x64.png "CivetWeb") CivetWeb +======= + +CivetWeb is an easy to use, powerful, C/C++ embeddable web server with optional CGI, SSL and Lua support. + +CivetWeb can be used by developers as a library, to add web server functionality to an existing application. +CivetWeb uses an [MIT license](https://github.com/civetweb/civetweb/blob/master/LICENSE.md). + +It can also be used by end users as a stand-alone web server. It is available as single executable, no installation is required. + +The current stable version is 1.9.1 - [release notes](https://github.com/civetweb/civetweb/blob/master/RELEASE_NOTES.md) + + +End users can download CivetWeb at SourceForge +[https://sourceforge.net/projects/civetweb/](https://sourceforge.net/projects/civetweb/) + +Developers can contribute to CivetWeb via GitHub +[https://github.com/civetweb/civetweb](https://github.com/civetweb/civetweb) + +Trouble tickets should be filed on GitHub +[https://github.com/civetweb/civetweb/issues](https://github.com/civetweb/civetweb/issues) + +Announcements are at Google Groups +[https://groups.google.com/d/forum/civetweb](https://groups.google.com/d/forum/civetweb) + +While older support question and discussion threads have been at [Google groups](https://groups.google.com/d/forum/civetweb), most newer ones are [GitHub issues](https://github.com/civetweb/civetweb/issues). + +Source releases can be found on GitHub +[https://github.com/civetweb/civetweb/releases](https://github.com/civetweb/civetweb/releases) + + +Documentation +--------------- + +- [Installing.md](Installing.md) - Install Guide (for end users using pre-built binaries) +- [UserManual.md](UserManual.md) - End User Guide +- [Building.md](Building.md) - Building the Server (quick start guide) +- [Embedding.md](Embedding.md) - Embedding (how to add HTTP support to an existing application) +- [OpenSSL.md](OpenSSL.md) - Adding HTTPS (SSL/TLS) support using OpenSSL. +- [API documentation](api) - Additional documentation on the civetweb application programming interface ([civetweb.h](https://github.com/civetweb/civetweb/blob/master/include/civetweb.h)). + +[Authors](https://github.com/civetweb/civetweb/blob/master/CREDITS.md) diff --git a/ceph/src/civetweb/docs/UserManual.md b/ceph/src/civetweb/docs/UserManual.md index 6b44b157e..3acf49272 100644 --- a/ceph/src/civetweb/docs/UserManual.md +++ b/ceph/src/civetweb/docs/UserManual.md @@ -140,11 +140,16 @@ Comma separated list of URI=PATH pairs, specifying that given URIs must be protected with password files specified by PATH. All Paths must be full file paths. -### authentication_domain `mydomain.com` +### authentication\_domain `mydomain.com` Authorization realm used for HTTP digest authentication. This domain is used in the encoding of the `.htpasswd` authorization files as well. Changing the domain retroactively will render the existing passwords useless. +### enable\_auth\_domain\_check `yes` +When using absolute URLs, verify the host is identical to the authentication\_domain. If enabled, requests to absolute URLs will only be processed +if they are directed to the domain. If disabled, absolute URLs to any host +will be accepted. + ### ssi\_pattern `**.shtml$|**.shtm$` All files that match `ssi_pattern` are treated as Server Side Includes (SSI). @@ -235,12 +240,19 @@ are additional default index files, ordered before `index.cgi`. ### enable\_keep\_alive `no` Enable connection keep alive, either `yes` or `no`. -Experimental feature. Allows clients to reuse TCP connection for subsequent -HTTP requests, which improves performance. +Allows clients to reuse TCP connection for subsequent HTTP requests, +which improves performance. For this to work when using request handlers it is important to add the correct Content-Length HTTP header for each request. If this is forgotten the client will time out. +Note: If you set keep\_alive to `yes`, you should set keep\_alive\_timeout\_ms +to some value > 0 (e.g. 500). If you set keep\_alive to `no`, you should set +keep\_alive\_timeout\_ms to 0. Currently, this is done as a default value, +but this configuration is redundant. In a future version, the keep\_alive +configuration option might be removed and automatically set to `yes` if +a timeout > 0 is set. + ### access\_control\_list An Access Control List (ACL) allows restrictions to be put on the list of IP addresses which have access to the web server. In the case of the Civetweb @@ -279,13 +291,42 @@ For example, to bind to a loopback interface on port 80 and to all interfaces on HTTPS port 443, use `127.0.0.1:80,443s`. If the server is built with IPv6 support, `[::]:8080` can be used to -listen to connections to port 8080 from both, IPv4 and IPv6. -IPv6 addresses of network interfaces can be specified as well, +listen to IPv6 connections to port 8080. IPv6 addresses of network +interfaces can be specified as well, e.g. `[::1]:8080` for the IPv6 loopback interface. +[::]:80 will bind to port 80 IPv6 only. In order to use port 80 for +all interfaces, both IPv4 and IPv6, use either the configuration +`80,[::]:80` (create one socket for IPv4 and one for IPv6 only), +or `+80` (create one socket for both, IPv4 and IPv6). +The `+`-notation to use IPv4 and IPv6 will only work in no network +interface is specified. Depending on your operating system version +and IPv6 network environment, some configurations might not work +as expected, so you have to test to find the configuration most +suitable for your needs. In case `+80` does not work for your +environment, you need to use `80,[::]:80`. + +It is possible to use network interface addresses (e.g., `192.0.2.3:80`, +`[2001:0db8::1234]:80`). To get a list of available network interface +addresses, use `ipconfig` (in a `cmd` window in Windows) or `ifconfig` +(in a Linux shell). +Alternatively, you could use the hostname for an interface. Check the +hosts file of your operating system for a proper hostname +(for Windows, usually found in C:\Windows\System32\drivers\etc\, +for most Linux distributions: /etc/hosts). E.g., to bind the IPv6 +local host, you could use `ip6-localhost:80`. This translates to +`[::1]:80`. Beside the hosts file, there are several other name +resolution services. Using your hostname might bind you to the +localhost or an external interface. You could also try `hostname.local`, +if the proper network services are installed (Zeroconf, mDNS, Bonjour, +Avahi). When using a hostname, you need to test in your particular network +environment - in some cases, you might need to resort to a fixed IP address. + ### document\_root `.` A directory to serve. By default, the current working directory is served. The current directory is commonly referenced as dot (`.`). +It is recommended to use an absolute path for document\_root, in order to +avoid accidentally serving the wrong directory. ### ssl\_certificate Path to the SSL certificate file. This option is only required when at least @@ -333,13 +374,47 @@ A pattern for the files to hide. Files that match the pattern will not show up in directory listing and return `404 Not Found` if requested. Pattern must be for a file name only, not including directory names. Example: - civetweb -hide_files_patterns secret.txt|*.hide + civetweb -hide_files_patterns secret.txt|**.hide + +Note: hide\_file\_patterns uses the pattern described above. If you want to +hide all files with a certain extension, make sure to use **.extension +(not just *.extension). ### request\_timeout\_ms `30000` Timeout for network read and network write operations, in milliseconds. If a client intends to keep long-running connection, either increase this value or (better) use keep-alive messages. +### keep\_alive\_timeout\_ms `500` or `0` +Idle timeout between two requests in one keep-alive connection. +If keep alive is enabled, multiple requests using the same connection +are possible. This reduces the overhead for opening and closing connections +when loading several resources from one server, but it also blocks one port +and one thread at the server during the lifetime of this connection. +Unfortunately, browsers do not close the keep-alive connection after loading +all resources required to show a website. +The server closes a keep-alive connection, if there is no additional request +from the client during this timeout. + +Note: if enable\_keep\_alive is set to `no` the value of +keep\_alive\_timeout\_ms should be set to `0`, if enable\_keep\_alive is set +to `yes`, the value of keep\_alive\_timeout\_ms must be >0. +Currently keep\_alive\_timeout\_ms is ignored if enable\_keep\_alive is no, +but future versions my drop the enable\_keep\_alive configuration value and +automatically use keep-alive if keep\_alive\_timeout\_ms is not 0. + +### linger\_timeout\_ms +Set TCP socket linger timeout before closing sockets (SO\_LINGER option). +The configured value is a timeout in milliseconds. Setting the value to 0 +will yield in abortive close (if the socket is closed from the server side). +Setting the value to -1 will turn off linger. +If the value is not set (or set to -2), CivetWeb will not set the linger +option at all. + +Note: For consistency with other timeouts, the value is configured in +milliseconds. However, the TCP socket layer usually only offers a timeout in +seconds, so the value should be an integer multiple of 1000. + ### lua\_preload\_file This configuration option can be used to specify a Lua script file, which is executed before the actual web page script (Lua script, Lua server page @@ -361,6 +436,25 @@ directly to the client. Lua script parts are delimited from the standard content by including them between tags. An example can be found in the test directory. +### lua\_background\_script +Experimental feature, and subject to change. +Run a Lua script in the background, independent from any connection. +The script is started before network access to the server is available. +It can be used to prepare the document root (e.g., update files, compress +files, ...), check for external resources, remove old log files, etc. + +The Lua state remains open until the server is stopped. +In the future, some callback functions will be available to notify the +script on changes of the server state. See example lua script : +[background.lua](https://github.com/civetweb/civetweb/blob/master/test/background.lua). + +Additional functions available in background script : +sleep, root path, script name, isterminated + +### lua\_background\_script\_params `param1=1,param2=2` +Can add dynamic parameters to background script. +Parameters mapped to global 'mg' table 'params' field. + ### websocket\_root In case civetweb is built with Lua and websocket support, Lua scripts may be used for websockets as well. Since websockets use a different URL scheme @@ -368,11 +462,38 @@ be used for websockets as well. Since websockets use a different URL scheme websockets may also be served from a different directory. By default, the document_root is used as websocket_root as well. -### access\_control\_allow\_origin + +### access\_control\_allow\_origin `*` Access-Control-Allow-Origin header field, used for cross-origin resource sharing (CORS). See the [Wikipedia page on CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). + +### access\_control\_allow\_methods `*` +Access-Control-Allow-Methods header field, used for cross-origin resource +sharing (CORS) pre-flight requests. +See the [Wikipedia page on CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). + +If set to an empty string, pre-flights will not be supported directly by the server, +but scripts may still support pre-flights by handling the OPTIONS method properly. +If set to "*", the pre-flight will allow whatever method has been requested. +If set to a comma separated list of valid HTTP methods, the pre-flight will return +exactly this list as allowed method. +If set in any other way, the result is unspecified. + + +### access\_control\_allow\_headers `*` +Access-Control-Allow-Headers header field, used for cross-origin resource +sharing (CORS) pre-flight requests. +See the [Wikipedia page on CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). + +If set to an empty string, pre-flights will not allow additional headers. +If set to "*", the pre-flight will allow whatever headers have been requested. +If set to a comma separated list of valid HTTP headers, the pre-flight will return +exactly this list as allowed headers. +If set in any other way, the result is unspecified. + + ### error\_pages This option may be used to specify a directory for user defined error pages. The error pages may be specified for an individual http status code (e.g., @@ -404,32 +525,44 @@ This value should not exceed one year (RFC 2616, Section 14.21). A value of 0 will send "do not cache" headers for all static files. For values <0 and values >31622400, the behavior is undefined. +### strict\_transport\_security\_max\_age + +Set the `Strict-Transport-Security` header, and set the `max-age` value. +This instructs web browsers to interact with the server only using HTTPS, +never by HTTP. If set, it will be sent for every request handled directly +by the server, except scripts (CGI, Lua, ..) and callbacks. They must +send HTTP headers on their own. + +The time is specified in seconds. If this configuration is not set, +or set to -1, no `Strict-Transport-Security` header will be sent. +For values <-1 and values >31622400, the behavior is undefined. + ### decode\_url `yes` URL encoded request strings are decoded in the server, unless it is disabled by setting this option to `no`. -### ssl_verify_peer `no` +### ssl\_verify\_peer `no` Enable client's certificate verification by the server. -### ssl_ca_path +### ssl\_ca\_path Name of a directory containing trusted CA certificates. Each file in the directory must contain only a single CA certificate. The files must be named by the subject name’s hash and an extension of “.0”. If there is more than one certificate with the same subject name they should have extensions ".0", ".1", ".2" and so on respectively. -### ssl_ca_file +### ssl\_ca\_file Path to a .pem file containing trusted certificates. The file may contain more than one certificate. -### ssl_verify_depth `9` +### ssl\_verify\_depth `9` Sets maximum depth of certificate chain. If client's certificate chain is longer than the depth set here connection is refused. -### ssl_default_verify_paths `yes` +### ssl\_default\_verify\_paths `yes` Loads default trusted certificates locations set at openssl compile time. -### ssl_cipher_list +### ssl\_cipher\_list List of ciphers to present to the client. Entries should be separated by colons, commas or spaces. @@ -440,7 +573,7 @@ colons, commas or spaces. See [this entry](https://www.openssl.org/docs/manmaster/apps/ciphers.html) in OpenSSL documentation for full list of options and additional examples. -### ssl_protocol_version `0` +### ssl\_protocol\_version `0` Sets the minimal accepted version of SSL/TLS protocol according to the table: Protocols | Value @@ -451,7 +584,7 @@ TLS1.0+TLS1.1+TLS1.2 | 2 TLS1.1+TLS1.2 | 3 TLS1.2 | 4 -### ssl_short_trust `no` +### ssl\_short\_trust `no` Enables the use of short lived certificates. This will allow for the certificates and keys specified in `ssl_certificate`, `ssl_ca_file` and `ssl_ca_path` to be exchanged and reloaded while the server is running. @@ -463,6 +596,44 @@ increase performance while swapping the certificate. Disk IO performance can be improved when keeping the certificates and keys stored on a tmpfs (linux) on a system with very high throughput. +### allow\_sendfile\_call `yes` +This option can be used to enable or disable the use of the Linux `sendfile` system call. It is only available for Linux systems and only affecting HTTP (not HTTPS) connections if `throttle` is not enabled. While using the `sendfile` call will lead to a performance boost for HTTP connections, this call may be broken for some file systems and some operating system versions. + +### case\_sensitive `no` +This option can be uset to enable case URLs for Windows servers. It is only available for Windows systems. Windows file systems are not case sensitive, but they still store the file name including case. If this option is set to `yes`, the comparison for URIs and Windows file names will be case sensitive. + +### allow\_index\_script\_resource `no` +Index scripts (like `index.cgi` or `index.lua`) may have script handled resources. + +It this feature is activated, that /some/path/file.ext might be handled by: + 1. /some/path/file.ext (with PATH\_INFO='/', if ext = cgi) + 2. /some/path/index.lua with mg.request\_info.path\_info='/file.ext' + 3. /some/path/index.cgi with PATH\_INFO='/file.ext' + 4. /some/path/index.php with PATH\_INFO='/file.ext' + 5. /some/index.lua with mg.request\_info.path\_info=='/path/file.ext' + 6. /some/index.cgi with PATH\_INFO='/path/file.ext' + 7. /some/index.php with PATH\_INFO='/path/file.ext' + 8. /index.lua with mg.request\_info.path\_info=='/some/path/file.ext' + 9. /index.cgi with PATH\_INFO='/some/path/file.ext' + 10. /index.php with PATH\_INFO='/some/path/file.ext' + +Note: This example is valid, if the default configuration values for `index_files`, `cgi_pattern` and `lua_script_pattern` are used, and the server is built with CGI and Lua support enabled. + +If this feature is not activated, only the first file (/some/path/file.cgi) will be accepted. + +Note: This parameter affects only index scripts. A path like /here/script.cgi/handle/this.ext will call /here/script.cgi with PATH\_INFO='/handle/this.ext', no matter if this option is set to `yes` or `no`. + +This feature can be used to completely hide the script extension from the URL. + +### additional\_header +Send additional HTTP response header line for every request. +The full header line including key and value must be specified, excluding the carriage return line feed. + +Example (used as command line option): +`-additional_header "X-Frame-Options: SAMEORIGIN"` + +This option can be specified multiple times. All specified header lines will be sent. + # Lua Scripts and Lua Server Pages Pre-built Windows and Mac civetweb binaries have built-in Lua scripting support as well as support for Lua Server Pages. @@ -528,7 +699,9 @@ mg (table): mg.read() -- reads a chunk from POST data, returns it as a string mg.write(str) -- writes string to the client - mg.include(path) -- sources another Lua file + mg.include(filename, [pathtype]) -- include another Lua Page file (Lua Pages only) + -- pathtype can be "abs", "rel"/"file" or "virt[ual]" + -- like defined for SSI #include mg.redirect(uri) -- internal redirect to a given URI mg.onerror(msg) -- error handler, can be overridden mg.version -- a string that holds Civetweb version @@ -537,6 +710,7 @@ mg (table): mg.get_var(str, varname) -- extract variable from (query) string mg.get_cookie(str, cookie) -- extract cookie from a string mg.get_mime_type(filename) -- get MIME type of a file + mg.get_info(infotype) -- get server status information mg.send_file(filename) -- send a file, including MIME type mg.url_encode(str) -- URL encode a string mg.url_decode(str, [form]) -- URL decode a string. If form=true, replace + by space. @@ -576,10 +750,13 @@ connect (function): end +All filename arguments are either absolute or relative to the civetweb working +directory (not the document root or the Lua script/page file). + **IMPORTANT: Civetweb does not send HTTP headers for Lua pages. Therefore, every Lua Page must begin with a HTTP reply line and headers**, like this: - + ... the rest of the web page ... @@ -616,6 +793,14 @@ An example is shown in Solution: specify the full path to the PHP interpreter, e.g.: `civetweb -cgi_interpreter /full/path/to/php-cgi` +- `php-cgi` is unavailable, for example on Mac OS X. As long as the `php` binary is installed, you can run CGI programs in command line mode (see the example below). Note that in this mode, `$_GET` and friends will be unavailable, and you'll have to parse the query string manually using [parse_str](http://php.net/manual/en/function.parse-str.php) and the `QUERY_STRING` environmental variable. + + #!/usr/bin/php + + - Civetweb fails to start. If Civetweb exits immediately when started, this usually indicates a syntax error in the configuration file (named `civetweb.conf` by default) or the command-line arguments. @@ -626,3 +811,4 @@ An example is shown in - Embedding with OpenSSL on Windows might fail because of calling convention. To force Civetweb to use `__stdcall` convention, add `/Gz` compilation flag in Visual Studio compiler. + diff --git a/ceph/src/civetweb/docs/_config.yml b/ceph/src/civetweb/docs/_config.yml new file mode 100644 index 000000000..259a24e4d --- /dev/null +++ b/ceph/src/civetweb/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-tactile \ No newline at end of file diff --git a/ceph/src/civetweb/docs/api/mg_callbacks.md b/ceph/src/civetweb/docs/api/mg_callbacks.md new file mode 100644 index 000000000..c7d69a134 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_callbacks.md @@ -0,0 +1,60 @@ +# Civetweb API Reference + +### `struct mg_callbacks;` + +### Fields + +| Field | Description | +| :--- | :--- | +|**`begin_request`**|**`int (*begin_request)( struct mg_connection *conn );`**| +| |The `begin_request()` callback function is called when CivetWeb has received a new HTTP request. If the callback function does not process the request, it should return 0. In that case CivetWeb will handle the request with the default callback routine. If the callback function returns a value between 1 and 999, CivetWeb does nothing and the callback function should do all the processing, including sending the proper HTTP headers etc. Starting at CivetWeb version 1.7, the function `begin_request()` is called before any authorization is done. If an authorization check is required, `request_handler()` should be used instead. The return value of the callback function is not only used to signal CivetWeb to not further process the request. The returned value is also stored as HTTP status code in the access log. | +|**`connection_close`**|**`void (*connection_close)( const struct mg_connection *conn );`**| +| |The callback function `connection_close()` is called when CivetWeb is closing a connection. The per-context mutex is locked when the callback function is invoked. The function is primarly useful for noting when a websocket is closing and removing it from any application-maintained list of clients. *Using this callback for websocket connections is deprecated. Use* `mg_set_websocket_handler()` *instead.*| +|**`end_request`**|**`void (*end_request)(const struct mg_connection *conn, int reply_status_code);`**| +| |The callback function `end_request()` is called by CivetWeb when a request has been completely processed. It sends the reply status code which was sent to the client to the application.| +|**`exit_context`**|**`void (*exit_context)( const struct mg_context *ctx );`**| +| |The callback function `exit_context()` is called by CivetWeb when the server is stopped. It allows the application to do some cleanup on the application side.| +|**`http_error`**|**`int (*http_error)( struct mg_connection *conn, int status );`**| +| |The callback function `http_error()` is called by CivetWeb just before an HTTP error is to be sent to the client. The function allows the application to send a custom error page. The status code of the error is provided as a parameter. If the application sends their own error page, it must return 1 to signal CivetWeb that no further processing is needed. If the returned value is 0, CivetWeb will send a built-in error page to the client.| +|**`init_context`**|**`void (*init_context)( const struct mg_context *ctx );`**| +| |The callback function `init_context()` is called after the CivetWeb server has been started and initialized, but before any requests are served. This allowes the application to perform some initialization activities before the first requests are handled.| +|**`init_lua`**|**`void (*init_lua)( const struct mg_connection *conn, void *lua_context );`**| +| |The callback function `init_lua()` is called just before a Lua server page is to be served. Lua page serving must have been enabled at compile time for this callback function to be called. The parameter `lua_context` is a `lua_State *` pointer.| +|**`init_ssl`**|**`int (*init_ssl)( void *ssl_context, void *user_data );`**| +| |The callback function `init_ssl()` is called when CivetWeb initializes the SSL library. The parameter `user_data` contains a pointer to the data which was provided to `mg_start()` when the server was started. The callback function can return 0 to signal that CivetWeb should setup the SSL certificate. With a return value of 1 the callback function signals CivetWeb that the certificate has already been setup and no further processing is necessary. The value -1 should be returned when the SSL initialization fails.| +|**`init_thread`**|**`void (*init_thread)( const struct mg_context *ctx, int thread_type );`**| +| |The callback function `init_thread()` is called when a new thread is created by CivetWeb. The `thread_type` parameter indicates which type of thread has been created. following thread types are recognized:| +| |**0** - The master thread is created | +| |**1** - A worker thread which handles client connections has been created| +| |**2** - An internal helper thread (timer thread) has been created| +|**`log_access`**|**`int (*log_access)( const struct mg_connection *conn, const char *message );`**| +| |The callback function `log_access()` is called when CivetWeb is about to log a message. If the callback function returns 0, CivetWeb will use the default internal access log routines to log the access. If a non-zero value is returned, CivetWeb assumes that access logging has already been done and no further action is performed.| +|**`log_message`**|**`int (*log_message)( const struct mg_connection *conn, const char *message );`**| +| |The callback function `log_message()` is called when CivetWeb is about to log a message. If the callback function returns 0, CivetWeb will use the default internal log routines to log the message. If a non-zero value is returned CivetWeb assumes that logging has already been done and no further action is performed.| +|**`open_file`**|**`const char *(*open_file)( const struct mg_connection *conn, const char *path, size_t *data_len );`**| +| |The callback function `open_file()` is called when a file is to be opened by CivetWeb. The callback can return a pointer to a memory location and set the memory block size in the variable pointed to by `data_len` to signal CivetWeb that the file should not be loaded from disk, but that instead a stored version in memory should be used. If the callback function returns NULL, CivetWeb will open the file from disk. This callback allows caching to be implemented at the application side, or to serve specific files from static memory instead of from disk.| +|~~`upload`~~|**`void (*upload)( struct mg_connection * conn, const char *file_name );`**| +| |*Deprecated. Use* `mg_handle_form_request()` *instead.* The callback function `upload()` is called when CivetWeb has uploaded a file to a temporary directory as result of a call to `mg_upload()`. The parameter `file_name` contains the full file name including path to the uploaded file.| +|~~`websocket_connect`~~|**`int (*websocket_connect)( const struct mg_connection *conn );`**| +| |*Deprecated. Use* `mg_set_websocket_handler()` *instead.* The callback function `websocket_connect()` is called when a websocket request is received, before the actual websocket handshake has taken place. The callback function can signal to CivetWeb if it should accept or deny the incoming request with one of the following return values: | +| |**0** - CivetWeb can proceed with the handshake to accept the connection | +| |**1** - CivetWeb must close the connection immediately without performing a handshake | +|~~`websocket_data`~~|**`int (*websocket_data)( struct mg_connection *conn, int bits, char *data, size_t data_len );`**| +| |*Deprecated. Use* `mg_set_websocket_handler()` *instead.* The callback function `websocket_data()` is called when a data frame has been received from the client. The parameters contain the following information: | +| | **`bits`** - The first byte of the websocket frame. See [RFC-6455](http://tools.ietf.org/html/rfc6455) at section 5.2 for more information. | +| | **`data`** - The pointer to the received data block. Masks--if any--have already been applied. | +| | **`data_len`** - The length of the received data block | +| | If the application wants to keep the websocket open to receive more data, the callback function should return the value **1**. If the value **0** is returned by the callback function, CivetWeb will close the websocket connection and no more frames will be received.| +|~~`websocket_ready`~~|**`int (*websocket_ready)( struct mg_connection *conn );`**| +| |*Deprecated. Use* `mg_set_websocket_handler()` *instead.* The callback function `websocket_ready()` is called after the handshake of a websocket connection has succeeded succesfully to signal the application that the connection is ready for use. | + +### Description + +Much of the functionality in the Civetweb library is provided through callback functions. The application registers their own processing functions with the Civetweb library and when an event happens, the appropriate callback function is called. In this way an application is able to have their processing code right at the heart of the webserver, without the need to change the code of the webserver itself. A number of callback functions are registered when the civetweb subsystem is started. Other may be added or changed at runtime with helper functions. + +A pointer to a `mg_callbacks` structure is passed as parameter to the [`mg_start()`](mg_start.md) function to provide links to callback functions which the webserver will call at specific events. If a specific callback function is not supplied, CivetWeb will fallback to default internal callback routines. Callback functions give the application detailed control over how specific events should be handled. + +### See Also + +* [`mg_start();`](mg_start.md) +* [`mg_stop();`](mg_stop.md) diff --git a/ceph/src/civetweb/docs/api/mg_check_digest_access_authentication.md b/ceph/src/civetweb/docs/api/mg_check_digest_access_authentication.md new file mode 100644 index 000000000..fec3ad3ba --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_check_digest_access_authentication.md @@ -0,0 +1,37 @@ +# Civetweb API Reference + +### `mg_check_digest_access_authentication( conn, realm, filename );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`| A pointer to the connection to be used to send data | +|**`realm`**|`const char *`| The requested authentication realm or NULL | +|**`filename`**|`const char *`| The path to the passwords file | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`| An integer indicating success or failure | + +### Description + +This function can be used to check if a request header contains HTTP digest authentication +information, matching user and password encoded within the password file. +If the authentication realm (also called authentication domain) is NULL, the parameter +`authentication_domain` as specified in the server configuration (`mg_start()`) is used. + +A positive return value means, the user name, realm and a correct password hash have been +found in the passwords file. +A return of 0 means, reading the password file succeeded, but there was no matching user, +realm and password. +The function returns a negative number on errors. + +### See Also + +* [`mg_send_digest_access_authentication_request();`](mg_send_digest_access_authentication_request.md) +* [`mg_modify_passwords_file();`](mg_modify_passwords_file.md) +* [`mg_start();`](mg_start.md) + diff --git a/ceph/src/civetweb/docs/api/mg_check_feature.md b/ceph/src/civetweb/docs/api/mg_check_feature.md new file mode 100644 index 000000000..1da1b0721 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_check_feature.md @@ -0,0 +1,40 @@ +# Civetweb API Reference + +### `mg_check_feature( feature );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`feature`**|`unsigned`| A value indicating the feature to be checked | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`unsigned`| A value indicating if a feature is available. A positive value indicates available, while **0** is returned for an unavailable feature | + +### Description + +The function `mg_check_feature()` can be called from an application program to check of specific features have been compiled in the civetweb version which the application has been linked to. The feature to check is provided as an unsigned integer parameter. If the function is available in the currently linked library version, a value **> 0** is returned. Otherwise the function `mg_check_feature()` returns the value **0**. + +The following parameter values can be used: + +| Value | Compilation option | Description | +| :---: | :---: | :--- | +| **1** | NO_FILES | *Able to serve files*. If this feature is available, the webserver is able to serve files directly from a directory tree. | +| **2** | NO_SSL | *Support for HTTPS*. If this feature is available, the webserver van use encryption in the client-server connection. SSLv2, SSLv3, TLSv1.0, TLSv1.1 and TLSv1.2 are supported depending on the SSL library CivetWeb has been compiled with, but which protocols are used effectively when the server is running is dependent on the options used when the server is started. | +| **4** | NO_CGI | *Support for CGI*. If this feature is available, external CGI scripts can be called by the webserver. | +| **8** | USE_IPV6 | *Support IPv6*. The CivetWeb library is capable of communicating over both IPv4 and IPv6, but IPv6 support is only available if it has been enabled at compile time. | +| **16** | USE_WEBSOCKET | Support for web sockets. WebSockets support is available in the CivetWeb library if the proper options has been used during cimpile time. | +| **32** | USE_LUA | *Support for Lua scripts and Lua server pages*. CivetWeb supports server side scripting through the Lua language, if that has been enabled at compile time. Lua is an efficient scripting language which is less resource heavy than for example PHP. | +| **64** | USE_DUKTAPE | *Support for server side JavaScript*. Server side JavaScript can be used for dynamic page generation if the proper options have been set at compile time. Please note that client side JavaScript execution is always available if it has been enabled in the connecting browser. | +| **128** | NO_CACHING | *Support for caching*. The webserver will support caching, if it has not been disabled while compiling the library. | + +Parameter values other than the values mentioned above will give undefined results. Therefore—although the parameter values for the `mg_check_feature()` function are effectively bitmasks, you should't assume that combining two of those values with an OR to a new value will give any meaningful results when the function returns. + +### See Also + +* [`mg_get_option();`](mg_get_option.md) +* [~~`mg_get_valid_option_names();`~~](mg_get_valid_option_names.md) +* [`mg_get_valid_options();`](mg_get_valid_options.md) diff --git a/ceph/src/civetweb/docs/api/mg_client_cert.md b/ceph/src/civetweb/docs/api/mg_client_cert.md new file mode 100644 index 000000000..c81fbd080 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_client_cert.md @@ -0,0 +1,21 @@ +# Civetweb API Reference + +### `struct mg_client_cert;` + +### Fields + +| Field | Type | Description | +| :--- | :--- | :--- | +|**`subject`**|`const char *`| The subject of the certificate | +|**`issuer`**|`const char *`| The issuer of the certificate | +|**`serial`**|`const char *`| The serial number of the certificate | +|**`finger`**|`const char *`| The fingerprint of the certificate | + +### Description + +The structure `client_cert` is used as a sub-structure in the [`mg_request_info`](mg_request_info.md) structure to store information of an optional client supplied certificate. + +### See Also + +* [`struct mg_request_info;`](mg_request_info.md) +* [`mg_get_request_info();`](mg_get_request_info.md) diff --git a/ceph/src/civetweb/docs/api/mg_client_options.md b/ceph/src/civetweb/docs/api/mg_client_options.md new file mode 100644 index 000000000..f3b9b6823 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_client_options.md @@ -0,0 +1,21 @@ +# Civetweb API Reference + +### `struct mg_client_options;` + +### Fields + +| Field | Type | Description | +| :--- | :--- | :--- | +|**`host`**|`const char *`|The hostname or IP address to connect to| +|**`port`**|`int`|The port on the server| +|**`client_cert`**|`const char *`|Pointer to client certificate| +|**`server_cert`**|`const char *`|Pointer to a server certificate| + +### Description + +The the `mgclient_options` structure contains host and security information to connect as a client to another host. A parameter of this type is used in the call to the function [`mg_connect_client_secure();`](mg_connect_client_secure.md). Please note that IPv6 addresses are only permitted if IPv6 support was enabled during compilation. You can use the function [`mg_check_feature()`](mg_check_feature.md) with the parameter `USE_IPV6` while running your application to check if IPv6 is supported. + +### See Also + +* [`mg_check_feature();`](mg_check_feature.md) +* [`mg_connect_client_secure();`](mg_connect_client_secure.md) diff --git a/ceph/src/civetweb/docs/api/mg_close_connection.md b/ceph/src/civetweb/docs/api/mg_close_connection.md new file mode 100644 index 000000000..ca8d2a109 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_close_connection.md @@ -0,0 +1,21 @@ +# Civetweb API Reference + +### `mg_close_connection( conn );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|The connection which must be closed| + +### Return Value + +*none* + +### Description + +The function `mg_close_connection()` is used to close a connection which was opened with the [`mg_download()`](mg_download.md) function. Use of this function to close a connection which was opened in another way is undocumented and may give unexpected results. + +### See Also + +* [`mg_download();`](mg_download.md) diff --git a/ceph/src/civetweb/docs/api/mg_connect_client.md b/ceph/src/civetweb/docs/api/mg_connect_client.md new file mode 100644 index 000000000..e2aa77398 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_connect_client.md @@ -0,0 +1,29 @@ +# Civetweb API Reference + +### `mg_connect_client( host, port, use_ssl, error_buffer, error_buffer_size );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`host`**|`const char *`|hostname or IP address of the server| +|**`port`**|`int`|The port to connect to on the server| +|**`use_ssl`**|`int`|Connects using SSL of this value is not zero| +|**`error_buffer`**|`char *`|Buffer to store an error message| +|**`error_buffer_size`**|`size_t`|Maximum size of the error buffer including the NUL terminator| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`struct mg_connection *`|| + +### Description + +The function `mg_connect_client()` connects to a TCP server as a client. This server can be a HTTP server but this is not necessary. The function returns a pointer to a connection structure when the connection is established and NULL otherwise. The host may be on IPv4 or IPv6, but IPv6 is not enabled in every Civetweb installation. Specifically the use of IPv6 communications has to be enabled when the library is compiled. At runtime you can use the [`mg_check_feature()`](mg_check_feature.md) function with the parameter `USE_IPV6` to check if IPv6 communication is supported. + +### See Also + +* [`mg_check_feature();`](mg_check_feature.md) +* [`mg_connect_client_secure();`](mg_connect_client_secure.md) +* [`mg_connect_websocket_client();`](mg_connect_websocket_client.md) diff --git a/ceph/src/civetweb/docs/api/mg_connect_client_secure.md b/ceph/src/civetweb/docs/api/mg_connect_client_secure.md new file mode 100644 index 000000000..a87949b6a --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_connect_client_secure.md @@ -0,0 +1,30 @@ +# Civetweb API Reference + +### `mg_connect_client_secure( client_options, error_buffer, error_buffer_size );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`client_options`**|`const struct mg_client_options *`|Settings about the server connection| +|**`error_buffer`**|`char *`|Buffer to store an error message| +|**`error_buffer_size`**|`size_t`|Size of the error message buffer including the NUL terminator| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`struct mg_connection *`|| + +### Description + +The function `mg_connect_client_secure()` creates a secure connection with a server. The information about the connection and server is passed in a structure and an error message may be returned in a local buffer. The function returns a pointer to a `struct mg_connection` structure when successful and NULL otherwise. + +Please note that IPv6 communication is supported by Civetweb, but only if the use of IPv6 was enabled at compile time. The check while running a program if IPv6 communication is possible you can call [`mg_check_feature()`](mg_check_feature.md) with the `USE_IPV6` parameter to check if IPv6 communications can be used. + +### See Also + +* [`struct mg_client_options;`](mg_client_options.md) +* [`mg_check_feature();`](mg_check_feature.md) +* [`mg_connect_client();`](mg_connect_client.md) +* [`mg_connect_websocket_client();`](mg_connect_websocket_client.md) diff --git a/ceph/src/civetweb/docs/api/mg_connect_websocket_client.md b/ceph/src/civetweb/docs/api/mg_connect_websocket_client.md new file mode 100644 index 000000000..8562b25a7 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_connect_websocket_client.md @@ -0,0 +1,36 @@ +# Civetweb API Reference + +### `mg_connect_websocket_client( host, port, use_ssl, error_buffer, error_buffer_size, path, origin, data_func, close_func, user-data);` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`host`**|`const char *`|The hostname or IP address of the server| +|**`port`**|`int`|The port on the server| +|**`use_ssl`**|`int`|Use SSL if this parameter is not equal to zero| +|**`error_buffer`**|`char *`|Buffer to store an error message| +|**`error_buffer_size`**|`size_t`|Size of the error message buffer including the NUL terminator| +|**`path`**|`const char *`|The server path to connect to, for example `/app` if you want to connect to `localhost/app`| +|**`origin`**|`const char *`|The value of the `Origin` HTTP header| +|**`data_func`**|`mg_websocket_data_handler`|Callback which is used to process data coming back from the server| +|**`close_func`**|`mg_websocket_close_handler`|Callback which is called when the connection is to be closed| +|**`user_data`**|`void *`|User supplied argument| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`struct mg_connection *`|A pointer to the connection structure, or NULL if connecting failed| + +### Description + +The function `mg_connect_websocket_client()` connects to a websocket on a server as a client. Data and close events are processed with callback functions which must be provided in the call. + +Civetweb supports both IPv4 and IPv6 communication, but only if the use if IPv6 has been enabled at compile time. When running an application it is possible to check if IPv6 addressing is available by calling the [`mg_check_feature()`](mg_check_feature.md) function with the `USE_IPV6` parameter. + +### See Also + +* [`mg_check_feature();`](mg_check_feature.md) +* [`mg_connect_client();`](mg_connect_client.md) +* [`mg_connect_client_secure();`](mg_connect_client_secure.md) diff --git a/ceph/src/civetweb/docs/api/mg_cry.md b/ceph/src/civetweb/docs/api/mg_cry.md new file mode 100644 index 000000000..0cf45c9b1 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_cry.md @@ -0,0 +1,23 @@ +# Civetweb API Reference + +### `mg_cry( conn, fmt, ... );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`const struct mg_connection *`|The connection on which a problem occured| +|**`fmt`**|`const char *`|Format string without a line return| +|**`...`**|*various*|Parameters depending on the format string| + +### Return Value + +*none* + +### Description + +The function `mg_cry()` is called when something happens on a connection. The function takes a format string similar to the `printf()` series of functions with parameters and creates a text string which can then be used for logging. The `mg_cry()` function prints the output to the opened error log stream. Log messages can be processed with the `log_message()` callback function specified in the `struct mg_callbacks` structure. + +### See Also + +* [`struct mg_callbacks;`](mg_callbacks.md) diff --git a/ceph/src/civetweb/docs/api/mg_download.md b/ceph/src/civetweb/docs/api/mg_download.md new file mode 100644 index 000000000..1dbded0c7 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_download.md @@ -0,0 +1,37 @@ +# Civetweb API Reference + +### `mg_download( host, port, use_ssl, error_buffer, error_buffer_size, fmt, ... );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`host`**|`const char *`|The hostname or IP address of the server| +|**`port`**|`int`|The port number on the server| +|**`use_ssl`**|`int`|Use SSL if this value is not equal zero| +|**`error_buffer`**|`char *`|Buffer to store an error message| +|**`error_buffer_size`**|`size_t`|Size of the error message buffer including the terminating NUL| +|**`fmt`**|`const char *`|Format string specifying the remote command to execute| +|**`...`**|*various*|Parameters used in the format string| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`struct mg_connection *`|A pointer to the connection structure if successful and NULL otherwise| + +### Description + +The `mg_download()` function is used to download data from a remote webserver. The server address can either be specified as a hostname or IP address and SSL can be used if needed. If the function succeeds, a pointer is returned to a connection structure. The connection must be closed with a call to the [`mg_close_connection()`](mg_close_connection.md) function. + +The format string is a format string from the `printf()` series of functions to specify the remote command. An example to get the main index page from Google is the following call: + +`conn = mg_download( "google.com", 80, 0, ebuf, sizeof(ebuf), + "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n" );` + +Please note that although Civetweb supports both IPv4 and IPv6 communication that IPv6 addressing is only available if it was enabled at compile time. When running an application it is possible to check if IPv6 support has been compiled in by using the [`mg_check_feature()`](md_check_feature.md) function with the parameter `USE_IPV6`. + +### See Also + +* [`mg_check_feature();`](mg_check_feature.md) +* [`mg_close_connection();`](mg_close_connection.md) diff --git a/ceph/src/civetweb/docs/api/mg_exit_library.md b/ceph/src/civetweb/docs/api/mg_exit_library.md new file mode 100644 index 000000000..264340368 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_exit_library.md @@ -0,0 +1,29 @@ +# Civetweb API Reference + +### `mg_exit_library( );` + +### Parameters + +none + +### Return Value + +| Type | Description | +| :--- | :--- | +|`unsigned`| **0** is returned or error | + +### Description + +The function `mg_exit_library()` should be called from an application program, when the library should be unloaded. +It must be called only from one thread (it is not guaranteed to be thread safe). + +Only use `mg_exit_library( );` when you used [`mg_init_library( feature );`](api/mg_init_library.md) before. + +The library init and exit functions are new in version 1.9 (as dummy implementation) and effective only from version 1.10. +For compatibility reasons, other functions (such as [`mg_start();`](mg_start.md)) will initialize the required features as well, +but they will no longer do a de-initialization, leaving a memory leak when the library is unloaded. + +### See Also + +* [`mg_init_library( feature );`](mg_init_library.md) +* [`mg_check_feature( feature );`](mg_check_feature.md) diff --git a/ceph/src/civetweb/docs/api/mg_form_data_handler.md b/ceph/src/civetweb/docs/api/mg_form_data_handler.md new file mode 100644 index 000000000..2338b72a7 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_form_data_handler.md @@ -0,0 +1,36 @@ +# Civetweb API Reference + +### `struct mg_form_data_handler;` + +### Fields + +|Field|Description| +|:---|:---| +|**`field_found`**|**`int field_found( const char *key, const char *filename, char *path, size_t pathlen, void *user_data )`**;| +||The callback function `field_found()` is called when a new field has been found. The return value of this callback is used to define how the field should be processed. The parameters contain the following information:| +||**`key`** - The name of the field as it was named with the `name` tag in the HTML source.| +||**`filename`** - The name of the file to upload. Please not that this parameter is only valid when the input type was set to `file`. Otherwise this parameter has the value `NULL`.| +||**`path`** - This is an output parameter used to store the full name of the file including the path to store an incoming file at the computer. This parameter must be provided by the application to Civetweb when a form field of type `file` is found. Please not that together with setting this parameter, the callback function must return `FORM_FIELD_STORAGE_STORE`.i With any other return value the contents of the `path` buffer is ignored by Civetweb.| +||**`pathlen`** - The length of the buffer where the output path can be stored.| +||**`user_data`** - A pointer to the value of the field `user_data` of the structure `struct mg_form_data_handler`.| +||The callback function `field_found()` can return the following values back to Civetweb:| +||**`FORM_FIELD_STORAGE_SKIP`** - Ignore the field and continue with processing the next field| +||**`FORM_FIELD_STORAGE_GET`** - Call the callback function `field_get()` to receive the form data| +||**`FORM_FIELD_STORAGE_STORE`** - Store a file as `path` and overwrite that file if it already exists| +||**`FORM_FIELD_STORAGE_ABORT`** - Stop parsing the request and ignore all remaining form fields| +|**`field_get`**|**`int field_get( const char *key, const char *value, size_t valuelen, void *user_data );`**| +|**`field_store`**|**`int field_store( const char *path, long long file_size, void *user_data );`**| +||If the callback function `field_found()` returned `FORM_FIELD_STORAGE_STORE`, Civetweb will try to store the received data in a file. If writing the file is successful, the callback function `field_store()` is called. This function is only called after completion of a full upload, not if a file has only partly been uploaded. When only part of a file is received, Civetweb will delete that partly upload in the background and not inform the main application through this callback. The following parameters are provided in the function call:| +||**`path`** -| +||**`file_size`** - The path on the server where the file was stored| +||**`user_data`** - The size of the stored file in bytes| +|**`user_data`**|**`void *`** The value of the field `user_data` when the callback functions were registered with a call to `mg_handle_form_request();`| +||The `user_data` field is a user supplied argument that will be passed as parameter to each of callback functions| + +### Description + +The structure `struct mg_form_data_handler` contains callback functions for handling form fields. Form fields give additional information back from a web page to the server which can be processed by these callback functions. + +### See Also + +* [`mg_handle_form_request();`](mg_handle_form_request.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_builtin_mime_type.md b/ceph/src/civetweb/docs/api/mg_get_builtin_mime_type.md new file mode 100644 index 000000000..c9044ae1f --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_builtin_mime_type.md @@ -0,0 +1,24 @@ +# Civetweb API Reference + +### `mg_get_builtin_mime_type( file_name );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`file_name`**|`const char *`|The name of the file for which the MIME type has to be determined| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`const char *`|A text string describing the MIME type| + +### Description + +The function `mg_get_builtin_mime_type()` tries to determine the MIME type of a given file. If the MIME type cannot be determined, the value `text/plain` is returned. Please note that this function does not an intelligent check of the file contents. The MIME type is solely determined based on the file name extension. + +### See Also + +* [`mg_send_mime_file();`](mg_send_mime_file.md) +* [`mg_send_mime_file2();`](mg_send_mime_file2.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_connection_info.md b/ceph/src/civetweb/docs/api/mg_get_connection_info.md new file mode 100644 index 000000000..14a2f68cb --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_connection_info.md @@ -0,0 +1,40 @@ +# Civetweb API Reference + +### `mg_get_connection_info( ctx, idx, buffer, buflen );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`struct mg_context *`|The server context handle| +|**`idx`**|`int`|Connection index within the context| +|**`buffer**|`char *`|A string buffer to store the information| +|**`buflen**|`int`|Size of the string buffer (including space for a terminating 0)| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Available context information in bytes (excluding the terminating 0)| + +### Description + +The function `mg_get_connection_info()` returns statistics information collected for +a server connection index. This may be empty if the server has not been built with +statistics support (`#define USE_SERVER_STATS`). +If data is available, the returned string is in JSON format. The exact content may +vary, depending on the connection state and server version. + +### Note + +This is an experimental interface and may be changed, replaced +or even removed in the future. Currently the index `idx` must be +between `0` and `num_threads-1`. The thread is not locked for +performance reasons, so the information may be inconsistent +in rare cases. + +### See Also + +* [`mg_get_system_info();`](mg_get_system_info.md) +* [`mg_get_context_info();`](mg_get_context_info.md) + diff --git a/ceph/src/civetweb/docs/api/mg_get_context.md b/ceph/src/civetweb/docs/api/mg_get_context.md new file mode 100644 index 000000000..ce6cb2be2 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_context.md @@ -0,0 +1,24 @@ +# Civetweb API Reference + +### `mg_get_context( conn );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`const struct mg_connection *`|The connection for which the context has to be returned| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`struct mg_context *`|A pointer to the context of the given connection| + +### Description + +The function `mg_get_context()` returns the context associated with a connection. + +### See Also + +* [`mg_start();`](mg_start.md) +* [`mg_stop();`](mg_stop.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_context_info.md b/ceph/src/civetweb/docs/api/mg_get_context_info.md new file mode 100644 index 000000000..88ffcf742 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_context_info.md @@ -0,0 +1,32 @@ +# Civetweb API Reference + +### `mg_get_context_info( ctx, buffer, buflen );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`struct mg_context *`|The server context handle| +|**`buffer**|`char *`|A string buffer to store the information| +|**`buflen**|`int`|Size of the string buffer (including space for a terminating 0)| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Available context information in bytes (excluding the terminating 0)| + +### Description + +The function `mg_get_context_info()` returns statistics information collected for +the server context. This may be empty if the server has not been built with +statistics support (`#define USE_SERVER_STATS`). +If data is available, the returned string is in JSON format. The exact content may +vary, depending on the server state and server version. + +### See Also + +* [`mg_get_system_info();`](mg_get_system_info.md) +* [`mg_get_connection_info();`](mg_get_connection_info.md) + + diff --git a/ceph/src/civetweb/docs/api/mg_get_cookie.md b/ceph/src/civetweb/docs/api/mg_get_cookie.md new file mode 100644 index 000000000..a738bc07d --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_cookie.md @@ -0,0 +1,29 @@ +# Civetweb API Reference + +### `mg_get_cookie( cookie, var_name, buf, buf_len );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`cookie`**|`const char *`|The cookie name| +|**`var_name`**|`const char *`|The variable name| +|**`buf`**|`char *`|The buffer where to store the contents of the cookie| +|**`buf_len`**|`size_t`|The length of the cookie buffer, including the terminating NUL| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|The length of the cookie or an error code| + +### Description + +The function `mg_get_cookie()` tries to fetch the value of a certain cookie variable. The contents will either be stored in an application provided buffer, or an error code will be returned. The destination buffer is guaranteed to be NUL terminated if the pointer of the buffer is not a NULL pointer and the size of the buffer is at least one byte. + +If the function succeeds, the return value of the function is the length in bytes of the cookie. The value **`-1`** is returned if the requested cookie could not be found and **`-2`** if the destination buffer is represented by a NULL pointer, is zero length or too short to store the whole cookie. + +### See Also + +* [`mg_get_var();`](mg_get_var.md) +* [`mg_get_var2();`](mg_get_var2.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_header.md b/ceph/src/civetweb/docs/api/mg_get_header.md new file mode 100644 index 000000000..8ad1810ac --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_header.md @@ -0,0 +1,22 @@ +# Civetweb API Reference + +### `mg_get_header( conn, name );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`| A pointer referencing the connection | +|**`name`**|`const char *`| The name of the request header | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`const char *`| A pointer to the value of the request header, or NULL of no matching header count be found | + +### Description + +HTTP and HTTPS clients can send request headers to the server to provide details about the communication. These request headers can for example specify the preferred language in which the server should respond and the supported compression algorithms. The function `mg_get_header()` can be called to return the contents of a specific request header. The function will return a pointer to the value text of the header when succesful, and NULL of no matching request header from the client could be found. + +### See Also diff --git a/ceph/src/civetweb/docs/api/mg_get_option.md b/ceph/src/civetweb/docs/api/mg_get_option.md new file mode 100644 index 000000000..b731dd74f --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_option.md @@ -0,0 +1,24 @@ +# Civetweb API Reference + +### `mg_get_option( ctx, name );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`const struct mg_context *`| A pointer to the webserver context | +|**`name`**|`const char *`| The name of the option to query | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`const char *`| A pointer to the option value in text, or NULL if an error occured | + +### Description + +When starting the CivetWeb webserver, options are provided to set the wanted behaviour of the server. The options which were used during startup can be queried through the `mg_get_option()` function. Options are read-only and cannot be changed while the webserver is running. The function returns a pointer to a text string containing the value of the queried option, or NULL if an error occured. It is guaranteed however that if a valid option name is provided as a parameter to this function, that a pointer to a string is returned and not NULL. In case an option was empty or NULL during initialisation, `mg_get_option()` will return a pointer to an empty string. + +### See Also + +* [`mg_start();`](mg_start.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_ports.md b/ceph/src/civetweb/docs/api/mg_get_ports.md new file mode 100644 index 000000000..ba492ca36 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_ports.md @@ -0,0 +1,31 @@ +# Civetweb API Reference + +### ~~`mg_get_ports( ctx, size, ports, ssl );`~~ + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`const struct mg_context *`|| +|**`size`**|`size_t`|The number of ports which can be stored in the buffer| +|**`ports`**|`int *`|Buffer for storage of the port numbers| +|**`ssl`**|`int *`|Buffer used to store if SSL is used for the ports| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`size_t`|The number of ports stored in the buffer| + +### Description + +This function is deprecated. Use [`mg_get_server_ports()`](mg_get_server_ports.md) instead. + +The function `mg_get_ports()` returns a list of ports the Civetweb server is listening on. The port numbers are stored in a buffer of integers which is supplied by the calling party. The function also stores information if SSL is used on the ports. This information is stored in a second buffer which should be capable of storing the same amount of items as the ports buffer. + +The function returns the number of ports actually stored in the buffer. + +### See Also + +* [`struct mg_server_ports;`](mg_server_ports.md) +* [`mg_get_server_ports();`](mg_get_server_ports.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_request_info.md b/ceph/src/civetweb/docs/api/mg_get_request_info.md new file mode 100644 index 000000000..b7ddd07aa --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_request_info.md @@ -0,0 +1,28 @@ +# Civetweb API Reference + +### `mg_get_request_info( conn );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`const struct mg_connection *`|The connection for which the request info is needed| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`const struct mg_request_info *`|Pointer to the requested info, or NULL if an error occured| + +### Description + +The function `mg_get_request_info()` returns information about the request on a given connection. This information is returned as a pointer to a [`mg_request_info`](mg_request_info.md) structure. If an error occurs, a NULL pointer is returned instead. + +Use this function when implementing a server. + +### See Also + +* [`struct mg_request_info;`](mg_request_info.md) +* [`mg_get_response_info();`](mg_get_response_info.md) +* [`struct mg_response_info;`](mg_response_info.md) + diff --git a/ceph/src/civetweb/docs/api/mg_get_request_link.md b/ceph/src/civetweb/docs/api/mg_get_request_link.md new file mode 100644 index 000000000..d58a59285 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_request_link.md @@ -0,0 +1,29 @@ +# Civetweb API Reference + +### `mg_get_request_link( conn, buf, buflen );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`| A pointer referencing the connection | +|**`buf`**|`char *`| A buffer to store the link | +|**`buflen`**|`size_t`| Size of the buffer | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`| Return code: <0 for error, >=0 for success | + +### Description + +Store a formatted link corresponding to the current request. + +E.g., returns +`http://mydomain.com:8080/path/to/callback.ext` +or +`http://127.0.0.1:8080/path/to/callback.ext` +depending on the auth check settings. + +### See Also diff --git a/ceph/src/civetweb/docs/api/mg_get_response.md b/ceph/src/civetweb/docs/api/mg_get_response.md new file mode 100644 index 000000000..3e7b72711 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_response.md @@ -0,0 +1,29 @@ +# Civetweb API Reference + +### `mg_get_response( conn, ebuf, ebuf_len, timeout );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|The connection to listen on| +|**`ebuf`**|`char *`|Buffer to store an error message| +|**`ebuf_len`**|`size_t`|Size of the error message buffer including the terminating NUL| +|**`timeout`**|`int`|Time to wait for a response in milliseconds| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Success value of the wait| + +### Description + +The function `mg_get_reponse()` wait for a response from a remote server. A return value equal or greater than zero is an indication for success, a negative value us used to signal an error condition. A timeout can be specified which lets the function return after a specified number of milliseconds, even if no data is received from the remote party. If the timeout value is negative, the function will not return until data has been read or an unrecoverable error occurs. + +Error messages are stored in a caller supplied error message buffer. + +### See Also + +* [`mg_connect_client();`](mg_connect_client.md) +* [`mg_connect_client_secure();`](mg_connect_client_secure.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_response_code_text.md b/ceph/src/civetweb/docs/api/mg_get_response_code_text.md new file mode 100644 index 000000000..79ffa13ce --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_response_code_text.md @@ -0,0 +1,25 @@ +# Civetweb API Reference + +### `mg_get_response_code_text( conn, response_code );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`| A pointer referencing the connection | +|**`response_code`**|`int`| Response code for which the text is queried | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`const char *`| A pointer to a human readable text explaining the response code. | + +### Description + +The function `mg_get_response_code_text()` returns a pointer to a human readable text describing the HTTP response code which was provided as a parameter. + +### See Also + +* [`mg_get_builtin_mime_type();`](mg_get_builtin_mime_type.md) +* [`mg_version();`](mg_version.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_response_info.md b/ceph/src/civetweb/docs/api/mg_get_response_info.md new file mode 100644 index 000000000..40e7ab88a --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_response_info.md @@ -0,0 +1,29 @@ +# Civetweb API Reference + +### `mg_get_response_info( conn );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`const struct mg_connection *`|The connection for which the response info is needed| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`const struct mg_request_info *`|Pointer to the requested info, or NULL if an error occured| + +### Description + +The function `mg_response_info()` returns information about a response on a client connection opened by `mg_connect_client()`. If an error occurs, a NULL pointer is returned instead. + +Use this function when implementing a client. + +### See Also + +* [`struct mg_response_info;`](mg_response_info.md) +* [`mg_connect_client();`](mg_connect_client.md) +* [`mg_get_request_info();`](mg_get_request_info.md) +* [`struct mg_request_info;`](mg_request_info.md) + diff --git a/ceph/src/civetweb/docs/api/mg_get_server_ports.md b/ceph/src/civetweb/docs/api/mg_get_server_ports.md new file mode 100644 index 000000000..323b47011 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_server_ports.md @@ -0,0 +1,28 @@ +# Civetweb API Reference + +### `mg_get_server_ports( ctx, size, ports );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`const struct mg_context *`|The context for which the server ports are requested| +|**`size`**|`int`|The size of the buffer to store the port information| +|**`ports`**|`struct mg_server_ports *`|Buffer to store the port information| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|The actual number of ports returned, or an error condition| + +### Description + +The `mg_get_server_ports()` returns a list with server ports on which the Civetweb server is listening. The ports are returned for a given context and stored with additional information like the SSL and redirection state in a list of structures. The list of structures must be allocated by the calling routine. The size of the structure is also passed to `mg_get_server_ports()`. + +The function returns the number of items in the list, or a negative value if an error occured. + +### See Also + +* [~~`mg_get_ports();`~~](mg_get_ports.md) +* [`struct mg_server_ports;`](mg_server_ports.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_system_info.md b/ceph/src/civetweb/docs/api/mg_get_system_info.md new file mode 100644 index 000000000..6add98d5a --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_system_info.md @@ -0,0 +1,30 @@ +# Civetweb API Reference + +### `mg_get_system_info( buffer, buflen );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`buffer**|`char *`|A string buffer to store the information| +|**`buflen**|`int`|Size of the string buffer (including space for a terminating 0)| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Available system information in bytes (excluding the terminating 0)| + +### Description + +The function `mg_get_system_info()` returns information collected for the system +(operating system, compiler, version, ...). +Currently this data is returned as string is in JSON format, but changes to the +format are possible in future versions. The exact content of the JSON object may vary, +depending on the operating system and server version. +This string should be included for support requests. + +### See Also + +* [`mg_get_context_info();`](mg_get_context_info.md) + diff --git a/ceph/src/civetweb/docs/api/mg_get_user_connection_data.md b/ceph/src/civetweb/docs/api/mg_get_user_connection_data.md new file mode 100644 index 000000000..2e24c1340 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_user_connection_data.md @@ -0,0 +1,23 @@ +# Civetweb API Reference + +### `mg_get_user_connection_data( conn );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`const struct mg_connection *`|The connection for which to return the user data| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`void *`|A pointer to the user data, or NULL if no user data was registered with the connection| + +### Description + +The function `mg_get_user_connection_data()` returns the user data associated with a connection. This user data is represented with a pointer which has been prevously registered with a call to [`mg_set_user_connection_data();`](mg_set_user_connection_data.md). With this function it is possible to pass state information between callback functions refering to a specific connection. + +### See Also + +* [`mg_set_user_connection_data();`](mg_set_user_connection_data.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_user_data.md b/ceph/src/civetweb/docs/api/mg_get_user_data.md new file mode 100644 index 000000000..87bbe04fa --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_user_data.md @@ -0,0 +1,23 @@ +# Civetweb API Reference + +### `mg_get_user_data( ctx );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`const struct mg_context *`|The context for which the user data is requested| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`void *`|| + +### Description + +The function `mg_get_user_data()` returns the user data associated with a Civetweb context. This is a pointer value which has previously been used in the call to [`mg_start()`](mg_start.md) to initialize the server context. + +### See Also + +* [`mg_start();`](mg_start.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_valid_option_names.md b/ceph/src/civetweb/docs/api/mg_get_valid_option_names.md new file mode 100644 index 000000000..c6b43ad7c --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_valid_option_names.md @@ -0,0 +1,24 @@ +# Civetweb API Reference + +### ~~`mg_get_valid_option_names();`~~ + +### Parameters + +*none* + +### Return Value + +| Type | Description | +| :--- | :--- | +|`const char **`|An array with strings where the even elements represent the option names, and the odd element the option values The array is NULL terminated.| + +### Description + +The function `mg_get_valid_option_names()` is depricated. Use [`mg_get_valid_options()`](mg_get_valid_options.md) instead. + +This function returns an array with option/value pairs describing the valid configuration options for Civetweb. En element value of NULL signals the end of the list. + +### See Also + +* [`struct mg_option;`](mg_option.md) +* [`mg_get_valid_options();`](mg_get_valid_options.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_valid_options.md b/ceph/src/civetweb/docs/api/mg_get_valid_options.md new file mode 100644 index 000000000..fd6755eb5 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_valid_options.md @@ -0,0 +1,22 @@ +# Civetweb API Reference + +### `mg_get_valid_options();` + +### Parameters + +*none* + +### Return Value + +| Type | Description | +| :--- | :--- | +|`const struct mg_option *`|An array with all valid configuration options| + +### Description + +The function `mg_get_valid_options()` returns an array with all valid configuration options of Civetweb. Each element in the array is a structure with three fields which represent the name of the option, the value of the option and the type of the value. The array is terminated with an element for which the name is `NULL`. See for more details about this structure the documentation of [`struct mg_option`](mg_option.md). + +### See Also + +* [`struct mg_option;`](mg_option.md) +* [`mg_start();`](mg_start.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_var.md b/ceph/src/civetweb/docs/api/mg_get_var.md new file mode 100644 index 000000000..c21c7bbd3 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_var.md @@ -0,0 +1,30 @@ +# Civetweb API Reference + +### `mg_get_var( data, data_len, var_name, dst, dst_len );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`data`**|`const char *`|Encoded buffer from either POST data or the URI of a GET call| +|**`data_len`**|`size_t`|Size of the encode buffer including the terminating NULL| +|**`var_name`**|`const char *`|Name of the variable to search for| +|**`dst`**|`char *`|Output buffer to store the content of the variable| +|**`dst_len`**|`size_t`|Length of the output buffer| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|The length of the variable or an error code| + +### Description + +The function `mg_get_var()` returns the value of a variable which is passed to the server with either a POST method, or as a parameter in the URI of a GET call. The data pointer passed to the function points to a form-URI encoded buffer. This can either be POST data or the `request_info.query_string`. The name of the searched variable and a buffer to store the results are also parameters to the function. + +The function either returns the length of the variable when successful, **`-1`** if the variable could not be found and **`-2`** if the destination buffer is NULL, has size zero or is too small to store the resulting variable value. + +### See Also + +* [`mg_get_cookie();`](mg_get_cookie.md) +* [`mg_get_var2();`](mg_get_var2.md) diff --git a/ceph/src/civetweb/docs/api/mg_get_var2.md b/ceph/src/civetweb/docs/api/mg_get_var2.md new file mode 100644 index 000000000..3a47d91a9 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_get_var2.md @@ -0,0 +1,31 @@ +# Civetweb API Reference + +### `mg_get_var2( data, data_len, var_name, dst, dst_len, occurrence );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`data`**|`const char *`|Encoded data buffer from either POST data or a GET URI| +|**`data_len`**|`size_t`|The size of the encoded data buffer| +|**`var_name`**|`const char *`|The name of the variable to search for| +|**`dst`**|`char *`|Destination buffer to store the variable content| +|**`dst_len`**|`size_t`|The size of the destination buffer including the terminating NUL| +|**`occurrence`**|`size_t`|The instance index of the wanted variable| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Length of the variable contents, or an error code| + +### Description + +The function `mg_get_var2()` can be used to return the contents of a variable passed to the server as either POST data, or in the URI in a GET call. The function is somilar to [`mg_get_var()`](mg_get_var.md) but the difference is that `mg_get_var2()` can be used if the same variable is present multiple times in the data. The `occurence` parameter is used to identify which instance of the variable must be returned where **`0`** is used for the first variable with the specified name, **`1`** for the second and so on. + +The function returns the length of the variable content in the return buffer, **`-1`** if a variable with the specified name could not be found and **`-2`** if the pointer to the result buffer is NULL, the size of the result buffer is zero or when the result buffer is too small to contain the variable content and terminating NUL. + +### See Also + +* [`mg_get_cookie();`](mg_get_cookie.md) +* [`mg_get_var();`](mg_get_var.md) diff --git a/ceph/src/civetweb/docs/api/mg_handle_form_request.md b/ceph/src/civetweb/docs/api/mg_handle_form_request.md new file mode 100644 index 000000000..4a1d888e3 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_handle_form_request.md @@ -0,0 +1,24 @@ +# Civetweb API Reference + +### `mg_handle_form_request( conn, fdh );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|The connection on which form data must be processed| +|**`fdh`**|`struct mg_form_data_handler`|Structure with callback functions to to the heavy work| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|The number of fields processed, or an error code| + +### Description + +The function `mg_handle_form_request()` processes form data on a connection. The function uses callback functions for the heavy lifting which are passed to the function as fields in a [`struct mg_form_data_handler`](mg_form_data_handler.md) structure. The number of processed fields is returned by the function, or a negative value when an error occured. I nthe situation where some fields are processed successfully (for example file downloads) and an error occurs later in the form processing, the function still returns a negative value. It is the responsibility of the calling party to do the necessary cleanup. The calling party should also do the cleanup of any files which are created, but not required anymore later. + +### See Also + +* [`struct mg_form_data_handler;`](mg_form_data_handler.md) diff --git a/ceph/src/civetweb/docs/api/mg_header.md b/ceph/src/civetweb/docs/api/mg_header.md new file mode 100644 index 000000000..403dc885f --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_header.md @@ -0,0 +1,18 @@ +# Civetweb API Reference + +### `struct mg_header;` + +### Fields + +| Field | Type | Description | +| :--- | :--- | :--- | +|**`name`**|`const char *`| The name of the client request header | +|**`value`**|`const char *`| The value of the client request header | + +### Description + +The structure `mg_header` is used as a sub-structure in the [`struct mg_request_info;`](mg_request_info.md) structure to store the name and value of one HTTP request header as sent by the client. + +### See Also + +* [`struct mg_request_info;`](mg_request_info.md) diff --git a/ceph/src/civetweb/docs/api/mg_init_library.md b/ceph/src/civetweb/docs/api/mg_init_library.md new file mode 100644 index 000000000..f0d2c4691 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_init_library.md @@ -0,0 +1,44 @@ +# Civetweb API Reference + +### `mg_init_library( feature );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`feature`**|`unsigned`| A bitmask indicating the features to be ininialized | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`unsigned`| A value indicating the initialized features is available. **0** is returned or error | + +### Description + +The function `mg_init_library()` should be called from an application program before using any other function. +It must be called only from one thread (it is not guaranteed to be thread safe). + +This function is new in version 1.9 (as dummy implementation) and effective only from version 1.10. +For compatibility reasons, other functions (such as [`mg_start();`](mg_start.md)) will initialize the required features as well, +but they will no longer do a de-initialization, leaving a memory leak when the library is unloaded. + +The following parameter values can be used: + +| Value | Compilation option | Description | +| :---: | :---: | :--- | +| **1** | NO_FILES | *Able to serve files*. If this feature is available, the webserver is able to serve files directly from a directory tree. | +| **2** | NO_SSL | *Support for HTTPS*. If this feature is available, the webserver van use encryption in the client-server connection. SSLv2, SSLv3, TLSv1.0, TLSv1.1 and TLSv1.2 are supported depending on the SSL library CivetWeb has been compiled with, but which protocols are used effectively when the server is running is dependent on the options used when the server is started. | +| **4** | NO_CGI | *Support for CGI*. If this feature is available, external CGI scripts can be called by the webserver. | +| **8** | USE_IPV6 | *Support IPv6*. The CivetWeb library is capable of communicating over both IPv4 and IPv6, but IPv6 support is only available if it has been enabled at compile time. | +| **16** | USE_WEBSOCKET | Support for web sockets. WebSockets support is available in the CivetWeb library if the proper options has been used during cimpile time. | +| **32** | USE_LUA | *Support for Lua scripts and Lua server pages*. CivetWeb supports server side scripting through the Lua language, if that has been enabled at compile time. Lua is an efficient scripting language which is less resource heavy than for example PHP. | +| **64** | USE_DUKTAPE | *Support for server side JavaScript*. Server side JavaScript can be used for dynamic page generation if the proper options have been set at compile time. Please note that client side JavaScript execution is always available if it has been enabled in the connecting browser. | +| **128** | NO_CACHING | *Support for caching*. The webserver will support caching, if it has not been disabled while compiling the library. | + +The parameters can added using bitwise or. Values above 255 are reserved, the behavior of the function is undefined if any unknown bit is set. + +### See Also + +* [`mg_check_feature( feature );`](api/mg_check_feature.md) +* [`mg_exit_library( feature );`](api/mg_exit_library.md) diff --git a/ceph/src/civetweb/docs/api/mg_lock_connection.md b/ceph/src/civetweb/docs/api/mg_lock_connection.md new file mode 100644 index 000000000..167f9228c --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_lock_connection.md @@ -0,0 +1,26 @@ +# Civetweb API Reference + +### `mg_lock_connection( conn );` + +### Parameters + +| Parameter | Type | Description | +|**`conn`**|`struct mg_connection *`|The connection to retrieve a lock| + +### Return Value + +*none* + +### Description + +The function `mg_lock_connection()` is specifically for websocket connections to lock connection. Using this function in combination with [`mg_unlock_connection();`](mg_unlock_connection.md) is necessary around [`mg_write()`](mg_write.md) and [`mg_printf()`](mg_printf.md) calls if the code has server-initiated communication, as well as with communication in direct response to a message. + +### See Also + +* [`mg_lock_context();`](mg_lock_context.md) +* [`mg_printf();`](mg_printf.md) +* [`mg_unlock_connection();`](mg_unlock_connection.md) +* [`mg_unlock_context();`](mg_unlock_context.md) +* [`mg_websocket_client_write();`](mg_websocket_client_write.md) +* [`mg_websocket_write();`](mg_websocket_write.md) +* [`mg_write();`](mg_write.md) diff --git a/ceph/src/civetweb/docs/api/mg_lock_context.md b/ceph/src/civetweb/docs/api/mg_lock_context.md new file mode 100644 index 000000000..8be6bac72 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_lock_context.md @@ -0,0 +1,23 @@ +# Civetweb API Reference + +### `mg_lock_context( ctx );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`struct mg_context *`|The context to put the lock on| + +### Return Value + +*none* + +### Description + +The function `mg_lock_context()` can be used to acquire a lock for exclusive access to resources which are shared between connection of threads. The lock is context wide. The lock must be released with a call to [`mg_unlock_context()`](mg_unlock_context.md). + +### See Also + +* [`mg_lock_connection();`](mg_lock_connection.md) +* [`mg_unlock_connection();`](mg_unlock_connection.md) +* [`mg_unlock_context();`](mg_unlock_context.md) diff --git a/ceph/src/civetweb/docs/api/mg_md5.md b/ceph/src/civetweb/docs/api/mg_md5.md new file mode 100644 index 000000000..067a6a2f8 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_md5.md @@ -0,0 +1,24 @@ +# Civetweb API Reference + +### `mg_md5( buf, ... );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`buf`**|`char[33]`|Storage buffer for the calculated MD5 sum| +|**`...`**|`char *, ...`|NULL terminated list of pointers to strings with data| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`char *`|Pointer to the resulting MD5 string| + +### Description + +The function `mg_md5()` caluclates the MD5 checksum of a NULL terminated list of NUL terminated ASCII strings. The MD5 checksum is returned in human readable format as an MD5 string in a caller supplied buffer. + +The function returns a pointer to the supplied result buffer. + +### See Also diff --git a/ceph/src/civetweb/docs/api/mg_modify_passwords_file.md b/ceph/src/civetweb/docs/api/mg_modify_passwords_file.md new file mode 100644 index 000000000..edb5f0214 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_modify_passwords_file.md @@ -0,0 +1,33 @@ +# Civetweb API Reference + +### `mg_modify_passwords_file( passwords_file_name, domain, user, password );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`passwords_file_name`**|`const char *`|The path to the passwords file| +|**`realm`**|`const char *`|The authentication realm (domain) of the user record| +|**`user`**|`const char *`|Username of the record to be added, changed or deleted| +|**`password`**|`const char *`|Password associated with the user or NULL if the record must be deleted| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Success or error code| + +### Description + +The function `mg_modify_passwords_file()` allows an application to manipulate .htpasswd files on the fly by adding, deleting and changing user records. This is one of the several ways to implement authentication on the server side. + +If the password parameter is not `NULL` an entry is added to the password file. An existing records is modified in that case. If `NULL` is used as the password the enrty is removed from the file. + +The function returns 1 when successful and 0 if an error occurs. + +### See Also + +* [`mg_check_digest_access_authentication();`](mg_check_digest_access_authentication.md) +* [`mg_send_digest_access_authentication_request();`](mg_send_digest_access_authentication_request.md) + + diff --git a/ceph/src/civetweb/docs/api/mg_option.md b/ceph/src/civetweb/docs/api/mg_option.md new file mode 100644 index 000000000..dd7f090f8 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_option.md @@ -0,0 +1,31 @@ +# Civetweb API Reference + +### `struct mg_option;` + +### Fields + +| Field | Type | Description | +| :--- | :--- | :--- | +|**`name`**|`const char *`|Name of the option| +|**`type`**|`int`|Type of the option| +|**`default_value`**|`const char *`|Value of the option| + +### Description + +A list of valid configuration options of the Civetweb instance can be retrieved with a call to [`mg_get_valid_options()`](mg_get_valid_options.md). This function fills a list of `struct mg_option` structures where the content of each structure represents a configuration option. Each structure contains three fields. One field contains the name of the option, the second contains the value of the option and the third is an identifier used to define the type of the option and how the value contents should be interpreted. + +The field `type` can be one of the following values: + +|Value|Description| +| :--- | :--- | +|**`CONFIG_TYPE_UNKNOWN`**|The type of the option value is unknown| +|**`CONFIG_TYPE_NUMBER`**|The option value is an integer| +|**`CONFIG_TYPE_STRING`**|The option value is a number| +|**`CONFIG_TYPE_FILE`**|The option value is a file name| +|**`CONFIG_TYPE_DIRECTORY`**|The option value is a directory name| +|**`CONFIG_TYPE_BOOLEAN`**|The option value is a boolean| +|**`CONFIG_TYPE_EXT_PATTERN`**|The option value is a list of regular expression patterns| + +### See Also + +* [`mg_get_valid_options();`](mg_get_valid_options.md) diff --git a/ceph/src/civetweb/docs/api/mg_printf.md b/ceph/src/civetweb/docs/api/mg_printf.md new file mode 100644 index 000000000..8beb9c076 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_printf.md @@ -0,0 +1,27 @@ +# Civetweb API Reference + +### `mg_printf( conn, fmt, ... );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|The connection over which the data must be sent| +|**`fmt`**|`const char *`|Format string| +|**`...`**|*various*|Parameters as specified in the format string| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Number of bytes written or an error code| + +### Description + +The function `mg_printf()` can be used to send formatted strings over a connection. The functionality is comparable to the `printf()` family of functions in the standard C library. The function returns **0** when the connection has been closed, **-1** if an error occurred and otherwise the number of bytes written over the connection. Except for the formatting part, the `mg_printf()` function is identical to the function [`mg_write()`](mg_write.md). + +### See Also + +* [`mg_websocket_client_write();`](mg_websocket_client_write.md) +* [`mg_websocket_write();`](mg_websocket_write.md) +* [`mg_write();`](mg_write.md) diff --git a/ceph/src/civetweb/docs/api/mg_read.md b/ceph/src/civetweb/docs/api/mg_read.md new file mode 100644 index 000000000..c7ec6c3df --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_read.md @@ -0,0 +1,26 @@ +# Civetweb API Reference + +### `mg_read( conn, buf, len );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`| A pointer referencing the connection | +|**`buf`**|`void *`| A pointer to the location where the received data can be stored | +|**`len`**|`size_t`| The maximum number of bytes to be stored in the buffer | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`| The number of read bytes, or a status indication | + +### Description + +The function `mg_read()` receives data over an existing connection. The data is handled as binary and is stored in a buffer whose address has been provided as a parameter. The function returns the number of read bytes when successful, the value **0** when the connection has been closed by peer and a negative value when no more data could be read from the connection. + +### See Also + +* [`mg_printf();`](mg_printf.md) +* [`mg_write();`](mg_write.md) diff --git a/ceph/src/civetweb/docs/api/mg_request_info.md b/ceph/src/civetweb/docs/api/mg_request_info.md new file mode 100644 index 000000000..cad6bbc3c --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_request_info.md @@ -0,0 +1,35 @@ +# Civetweb API Reference + +### `struct mg_request_info;` + +### Fields + +| Field | Type | Description | +| :--- | :--- | :--- | +|**`request_method`**|`const char *`| The request method used by the client for the connection this can be **GET**, **POST** or one of the other common HTTP request methods | +|**`request_uri`**|`const char *`| The absolute, relative or URL-encoded URI as it was sent in the request. Example: "http://mydomain.com:8080/path/to/file.ext" or "/path/to/file.ext", depending on the client. | +|**`local_uri`**|`const char *`| The relative URL-encoded URI as it references the local resource. If the request URI does not reference a resource on the local server, this field is NULL. Example: "/path/to/file.ext" (even if the client used "http://mydomain.com:8080/path/to/file.ext" in the request) | +|~~`uri`~~|`const char *`| *Deprecated. Use* `local_uri` *instead* | +|**`http_version`**|`const char *`| The HTTP version as mentioned in the client request. This can be "1.0", "1.1", etc. | +|**`query_string`**|`const char *`| The HTTP query string, defined as URL part after the first '?' character, not including '?'. NULL if there is no '?'. | +|**`remote_user`**|`const char *`| The name of the authenticated remote user, or NULL if no authentication was used. Only used for HTTP (digest) authentication, not for cookie based authentication. | +|**`remote addr`**|`char[48]`| The IP address of the remote client as a string. This can either represent an IPv4 or an IPv6 address. Example: "127.0.0.1" | +|~~`remote_ip`~~|`long`| *Deprecated. Use* `remote_addr` *instead* | +|**`content_length`**|`long long`| The content length of the request body. This value can be -1 if no content length was provided. The request may still have body data, but the server cannot determine the length until all data has arrived (e.g. when the client closes the connection, or the final chunk of a chunked request has been received). | +|**`remote_port`**|`int`| The port number at the client's side (an integer number between 1 and 65535). | +|**`is_ssl`**|`int`| 1 if the connection is over SSL (https), and 0 if it is a plain connection (http) | +|**`user_data`**|`void *`| A pointer to the `user_data` information which was provided as a parameter to `mg_start()`. | +|**`conn_data`**|`void *`| A pointer to connection specific user data | +|**`num_headers`**|`int`| The number of HTTP request headers sent by the client (see http_headers) | +|**`http_headers`**|`struct mg_header[64]`| Array of structures with the HTTP request headers sent by the client. For the number of filled header fields, ee num_headers. | +|**`client_cert`**|`struct mg_client_cert *`| Pointer to the client certificate information, when available. This field is only filled for https connections using client certificates. | + +### Description + +The `mg_request_info` structure contains the client information of an existing connection. + +### See Also + +* [`struct mg_client_cert;`](mg_client_cert.md) +* [`struct mg_header;`](mg_header.md) +* [`mg_get_request_info();`](mg_get_request_info.md) diff --git a/ceph/src/civetweb/docs/api/mg_response_info.md b/ceph/src/civetweb/docs/api/mg_response_info.md new file mode 100644 index 000000000..a348dfcd9 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_response_info.md @@ -0,0 +1,38 @@ +# Civetweb API Reference + +### `struct mg_response_info;` + +### Fields + +struct mg_response_info { + int status_code; /* E.g. 200 */ + const char *status_text; /* E.g. "OK" */ + const char *http_version; /* E.g. "1.0", "1.1" */ + + long long content_length; /* Length (in bytes) of the request body, + can be -1 if no length was given. */ + + int num_headers; /* Number of HTTP headers */ + struct mg_header + http_headers[MG_MAX_HEADERS]; /* Allocate maximum headers */ +}; + +| Field | Type | Description | +| :--- | :--- | :--- | +|**`status code`**|`int`| The HTTP response code received by the client. | +|**`status_text`**|`const char *`| The textual representation of the HTTP status code. | +|**`http_version`**|`const char *`| The HTTP version as mentioned in the client request. This can be "1.0", "1.1", etc. | +|**`content_length`**|`long long`| The content length of the request body. This value can be -1 if no content length was provided. The request may still have body data, but the server cannot determine the length until all data has arrived (e.g. when the client closes the connection, or the final chunk of a chunked request has been received). | +|**`num_headers`**|`int`| The number of HTTP request headers sent by the client (see http_headers) | +|**`http_headers`**|`struct mg_header[64]`| Array of structures with the HTTP request headers sent by the client. For the number of filled header fields, ee num_headers. | + +Note: This structure is not yet feature complete and will be extended in future versions. + +### Description + +The `mg_response_info` structure contains information on a completed request from a client. + +### See Also + +* [`struct mg_header;`](mg_header.md) +* [`mg_get_response_info();`](mg_get_response_info.md) diff --git a/ceph/src/civetweb/docs/api/mg_send_chunk.md b/ceph/src/civetweb/docs/api/mg_send_chunk.md new file mode 100644 index 000000000..895ffdc30 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_send_chunk.md @@ -0,0 +1,31 @@ +# Civetweb API Reference + +### `mg_send_chunk( conn, buf, len );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`| A pointer to the connection to be used to send data | +|**`chunk`**|`const void *`| A pointer to the blob of information to be sent | +|**`chunk_len`**|`size_t`| The amount of bytes to be sent | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`| An integer indicating the amount of bytes sent, or failure | + +### Description + +The function `mg_send_chunk()` can be used to send a blob of arbitrary data over a connection. +Only use this function after sending a complete HTTP request or response header with "Transfer-Encoding: chunked" set. Otherwise: use `mg_write()`. +The function returns a number **>0** if data was sent, the value **0** when the connection has been closed, and **-1** in case of an error. + +### See Also + +* [`mg_write();`](mg_write.md) +* [`mg_printf();`](mg_print.md) +* [`mg_lock_connection();`](mg_lock_connection.md) +* [`mg_unlock_connection();`](mg_unlock_connection.md) + diff --git a/ceph/src/civetweb/docs/api/mg_send_digest_access_authentication_request.md b/ceph/src/civetweb/docs/api/mg_send_digest_access_authentication_request.md new file mode 100644 index 000000000..d5af9dad1 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_send_digest_access_authentication_request.md @@ -0,0 +1,35 @@ +# Civetweb API Reference + +### `mg_send_digest_access_authentication_request( conn, realm );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`| A pointer to the connection to be used to send data | +|**`realm`**|`const char *`| The requested authentication realm or NULL | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`| An integer indicating success or failure | + +### Description + +This function can be used to send a HTTP Digest Authentication request to the client. +Browsers will react with repeating the request with user authentication data. +If they do not yet know the user authentication for the requested realm, they will show +a dialog to query username and password. +In case the authentication realm (also called domain) is NULL, the parameter +`authentication_domain` from the server configuration is used. +The function returns a negative number on errors. + +### See Also + +* [`mg_check_digest_access_authentication();`](mg_check_digest_access_authentication.md) +* [`mg_modify_passwords_file();`](mg_modify_passwords_file.md) +* [`mg_send_http_error();`](mg_send_http_error.md) +* [`mg_write();`](mg_write.md) +* [`mg_printf();`](mg_print.md) + diff --git a/ceph/src/civetweb/docs/api/mg_send_file.md b/ceph/src/civetweb/docs/api/mg_send_file.md new file mode 100644 index 000000000..bffe075da --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_send_file.md @@ -0,0 +1,25 @@ +# Civetweb API Reference + +### `mg_send_file( conn, path );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|The connection over which the file must be sent| +|**`path`**|`const char *`|The full path and filename of the file| + +### Return Value + +*none* + +### Description + +The function `mg_send_file()` sends the contents of a file over a connection to the remote peer. The function also adds the necessary HTTP headers. + +### See Also + +* [`mg_printf();`](mg_printf.md) +* [`mg_send_mime_file();`](mg_send_mime_file.md) +* [`mg_send_mime_file2();`](mg_send_mime_file2.md) +* [`mg_write();`](mg_write.md) diff --git a/ceph/src/civetweb/docs/api/mg_send_http_error.md b/ceph/src/civetweb/docs/api/mg_send_http_error.md new file mode 100644 index 000000000..0c18d3e9f --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_send_http_error.md @@ -0,0 +1,32 @@ +# Civetweb API Reference + +### `mg_send_http_error( conn, status_code, fmt, ... );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|The connection over which the data must be sent| +|**`status_code`**|`int`|The HTTP status code (see HTTP standard)| +|**`fmt`**|`const char *`|Format string for an error message| +|**`...`**|*various*|Parameters as specified in the format string| + +### Return Value + +| Type | Description | +| :--- | :--- | + + +### Description + +The function `mg_send_http_error()` can be used to send HTTP error messages from a server to a client. +The `status_code` must be one of the predefined HTTP standard error codes (e.g., "404" for "Not Found"). +The status text (e.g., "Not Found") for standard error codes is known by this function. +A body of the error message, to explain the error in more detail, can be specified using the `fmt` format specifier and additional arguments. The `fmt` format specifier works like for the `printf()` function in the standard C library. + + +### See Also + +* [`mg_printf();`](mg_printf.md) +* [`mg_write();`](mg_write.md) + diff --git a/ceph/src/civetweb/docs/api/mg_send_mime_file.md b/ceph/src/civetweb/docs/api/mg_send_mime_file.md new file mode 100644 index 000000000..424b0dc18 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_send_mime_file.md @@ -0,0 +1,27 @@ +# Civetweb API Reference + +### `mg_send_mime_file( conn, path, mime_type );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|The connection over which the file must be sent| +|**`path`**|`const char *`|The full path and filename of the file| +|**`mime_type`**|`const char *`|The mime type of the file, or NULL for automatic detection| + +### Return Value + +*none* + +### Description + +The function `mg_send_mime_file()` sends a file over a connection including the HTTP headers. The function is similar to the [`mg_send_file()`](mg_send_file.md) with the additional functionality that the MIME type of the file can be specified. If the `mime_type` parameter is NULL, the routine will try to determine the MIME type based on the extension of the filename. + +### See Also + +* [`mg_get_builtin_mime_type();`](mg_get_builtin_mime_type.md) +* [`mg_printf();`](mg_printf.md) +* [`mg_send_file();`](mg_send_file.md) +* [`mg_send_mime_file2();`](mg_send_mime_file2.md) +* [`mg_write();`](mg_write.md) diff --git a/ceph/src/civetweb/docs/api/mg_send_mime_file2.md b/ceph/src/civetweb/docs/api/mg_send_mime_file2.md new file mode 100644 index 000000000..1350df8d6 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_send_mime_file2.md @@ -0,0 +1,30 @@ +# Civetweb API Reference + +### `mg_send_mime_file2( conn, path, mime_type, additional_headers );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|The connection over which the file must be sent| +|**`path`**|`const char *`|The full path and filename of the file| +|**`mime_type`**|`const char *`|The mime type or NULL for automatic detection| +|**`additional_headers`**|`const char *`|Additional headers to be sent| + +### Return Value + +*none* + +### Description + +The function `mg_send_mime_file2()` can be used to send a file over a connection. The function is similar to [`mg_send_mime_file()`](mg_send_mime_file.md) with the additional functionality that user specified headers can be sent. The MIME type of the file can be specified in the function call, or will be automatically determined based on the extension of the filename if the `mime_type` parameter has the value NULL. + +Additional custom header fields can be added as a parameter. Please make sure that these header names begin with `X-` to prevent name clashes with other headers. If the `additional_headers` parameter is NULL, no custom headers will be added. + +### See Also + +* [`mg_get_builtin_mime_type();`](mg_get_builtin_mime_type.md) +* [`mg_printf();`](mg_printf.md) +* [`mg_send_file();`](mg_send_file.md) +* [`mg_send_mime_file();`](mg_send_mime_file.md) +* [`mg_write();`](mg_write.md) diff --git a/ceph/src/civetweb/docs/api/mg_server_ports.md b/ceph/src/civetweb/docs/api/mg_server_ports.md new file mode 100644 index 000000000..e969f0324 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_server_ports.md @@ -0,0 +1,24 @@ +# Civetweb API Reference + +### `struct mg_server_ports;` + +### Fields + +| Field | Type | Description | +| :--- | :--- | :--- | +|**`protocol`**|`int`|The protocol mask where `IPv4` is **1**, `IPv6` is **2** and both `IPv4` and `IPv6` is **3**| +|**`port`**|`int`|The port number on which the service listens| +|**`is_ssl`**|`int`|**0** for `HTTP` communication, **1** for `HTTPS`| +|**`is_redirect`**|`int`|**1** if all requests are redirected, otherwise **0**| +|**`_reserved1`**|`int`|Reserved for internal use| +|**`_reserved2`**|`int`|Reserved for internal use| +|**`_reserved3`**|`int`|Reserved for internal use| +|**`_reserved4`**|`int`|Reserved for internal use| + +### Description + +A call to the function [`mg_get_server_ports()`](mg_get_server_ports.md) returns a list of structures with information about each running Civetweb service. These structures are of type `struct mg_server_ports` and contain the base information of each service. + +### See Also + +* [`mg_get_server_ports();`](mg_get_server_ports.md) diff --git a/ceph/src/civetweb/docs/api/mg_set_auth_handler.md b/ceph/src/civetweb/docs/api/mg_set_auth_handler.md new file mode 100644 index 000000000..302324adb --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_set_auth_handler.md @@ -0,0 +1,30 @@ +# Civetweb API Reference + +### `mg_set_auth_handler( ctx, uri, handler, cbdata );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`struct mg_context *`|The context on which the handler must be set| +|**`uri`**|`const char *`|The URI for the authorization handler| +|**`handler`**|`mg_authorization_handler`|Callback function doing the actual authorization| +|**`cbdata`**|`void *`|Optional user data| + +`int mg_authorization_handler( struct mg_connection *conn, void *cbdata );` + +### Return Value + +*none* + +### Description + +The function `mg_set_auth_handler()` hooks an authorization function to an URI to check if a user is authorized to visit that URI. The check is performed by a callback function of type `mg_authorization_handler`. The callback function is passed two parameters: the current connection and a pointer to optional user defined data which was passed to `mg_set_auth_handler()` when the callback was hooked to the URI. + +The callback function can return **0** to deny access, and **1** to allow access. + +The `mg_set_auth_handler()` function is very similar in use to [`mg_set_request_handler()`](mg_set_request_handler.md). + +### See Also + +* [`mg_set_request_handler();`](mg_set_request_handler.md) diff --git a/ceph/src/civetweb/docs/api/mg_set_request_handler.md b/ceph/src/civetweb/docs/api/mg_set_request_handler.md new file mode 100644 index 000000000..95a09a08d --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_set_request_handler.md @@ -0,0 +1,26 @@ +# Civetweb API Reference + +### `mg_set_request_handler( ctx, uri, handler, cbdata );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`struct mg_context *`|The context where the handler must be active| +|**`uri`**|`const char *`|The URI to hook the handler on| +|**`handler`**|`mg_request_handler`|Callback function doing the heavy lifting| +|**`cbdata`**|`void *`|Optional user supplied data| + +`int mg_request_handler( struct mg_connection *conn, void *cbdata );` + +### Return Value + +*none* + +### Description + +The function `mg_set_request_handler()` hooks a callback function on a URI. That callback function is called whenever a client requests the specific URI. The callback function receives the connection information and optional user supplied data as parameters and can serve information back to the client. When the callback function does not send any information back to the client, it should return **0** to signal Civetweb that the Civetweb core should handle the request. A return value between 1 and 999 is used to tell Civetweb that the request has been handled and no further processing is necessary. The returned code is stored as the status code in the access log, it is therefore recommended, although not mandatory to return a status code which matches the state of the request. + +### See Also + +* [`mg_set_auth_handler();`](mg_set_auth_handler.md) diff --git a/ceph/src/civetweb/docs/api/mg_set_user_connection_data.md b/ceph/src/civetweb/docs/api/mg_set_user_connection_data.md new file mode 100644 index 000000000..adafc2290 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_set_user_connection_data.md @@ -0,0 +1,44 @@ +# Civetweb API Reference + +### `mg_set_user_connection_data( conn, data );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|connection to add the user data| +|**`data`**|`void *`|Pointer to the user data| + +### Return Value + +*none* + +### Description + +The function `mg_set_user_connection_data()` can be used to set a user defined +data pointer attached to a connection. This value can be read using +`mg_get_user_connection_data()`. +Any call to `mg_set_user_connection_data()` will overwrite a previously +assigned user data pointer. + +`mg_set_user_connection_data()` requires a non-const +`struct mg_connection *` to set the user data pointer. It is save to use the +`const struct mg_connection *` passed to a websocket connect handler (with a +const cast), since `const` just means you must not use `mg_read()` or +`mg_write()` in this context. + +Alternatively, you can use the `init_connection` callback in +`struct mg_callbacks` to set the user data pointer. +In this case, typically `init_connection` is used to allocate memory for +a user defined `struct`, while `connection_close` is used to free this +memory again. + + +### See Also + +* [`mg_get_user_connection_data();`](mg_get_user_connection_data.md) +* [`struct mg_callbacks`](mg_callbacks.md) +* [`mg_set_websocket_handler();`](mg_set_websocket_handler.md) +* [`mg_read();`](mg_read.md) +* [`mg_write();`](mg_write.md) + diff --git a/ceph/src/civetweb/docs/api/mg_set_websocket_handler.md b/ceph/src/civetweb/docs/api/mg_set_websocket_handler.md new file mode 100644 index 000000000..f838c81d0 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_set_websocket_handler.md @@ -0,0 +1,30 @@ +# Civetweb API Reference + +### `mg_set_websocket_handler( ctx, uri, connect_handler, ready_handler, data_handler, close_handler, cbdata );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`mg_context *`|The context in which to add the handlers| +|**`uri`**|`const char *`|The URI for which the handlers should be activated| +|**`connect_handler`**|`mg_websocket_connect_handler`|Handler called when a connect is signalled| +|**`ready_handler`**|`mg_websocket_ready_handler`|Handler called when the connection is ready| +|**`data_handler`**|`mg_websocket_data_handler`|Handler called when data is received| +|**`close_handler`**|`mg_websocket_close_handler`|Handler called when the connection closes| +|**`cbdata`**|`void *`|User defined data| + +`int mg_websocket_connect_handler( const struct mg_connection *conn, void *cbdata );` +`int mg_websocket_ready_handler( struct mg_connection *conn, void *cbdata );` +`int mg_websocket_data_handler( struct mg_connection *conn, int opcode, char * buf, size_t buf_len, void *cbdata );` +`int mg_websocket_close_handler( const struct mg_connection *conn, void *cbdata );` + +### Return Value + +*none* + +### Description + +The function `mg_set_websocket_handler()` connects callback functions to a websocket URI. The callback functions are called when a state change is detected on the URI like an incomming connection or data received from a remote peer. + +### See Also diff --git a/ceph/src/civetweb/docs/api/mg_start.md b/ceph/src/civetweb/docs/api/mg_start.md new file mode 100644 index 000000000..c597d5514 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_start.md @@ -0,0 +1,39 @@ +# Civetweb API Reference + +### `mg_start( callbacks, user_data, options );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`callbacks`**|`const struct mg_callbacks *`| A structure with optional callback functions to process requests from the web server | +|**`user_data`**|`void *`| A pointer to optional user data | +|**`options`**|`char **`| A list of options used to initialize the web server. The list consists of an NULL terminated list of option-value string pairs. | + +The option list can be used to set the following options: + +| Option | Default | Description | +| :--- | :--- | :--- | +| **`cgi_environment`** | *empty* | The option `cgi_environment` can contain extra variables to be passed to the CGI script in addition to the standard environment variables. The lust must be a comma separated list of name=value pairs like this: `VARIABLE1=VALUE1,VARIABLE2=VALUE2`.| +| **`cgi_interpreter`**| *empty* | The option `cgi_interpreter` can contain a path to an executable which will be used as a CGI interpreter for **all** CGI scripts regardless of the script file extension. If this option is not set (which is the default), CivetWeb looks at the first line of a CGI script to see if an interpreter is defined there. This first line is formatted as a shebang line as common in unix style shell scripts, but this will also work in Windows. For more information about the syntax, please see the Wikipedia page about the [shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\)).| +| | |For example on a Windows system where both PHP and Perl CGI scripts are used, `#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be the first line of the respective CGI scripts. Note that the paths should be either full file paths, or file paths relative to the current working directory of the CivetWeb server. The current working directory may be dependent on the way the application is started. When started from the command line it is the directory from where the executable was called, but when starting it from a shortcut in a graphical desktop environment, it will be the directory where the executable is located, the default directory of the user or a directory mentioned in the shortcut, depending on the operating system and graphical user interface used.| +| | |If all CGIs use the same interpreter, it is more efficient to set the option `cgi_interpreter` to the path to that executable because in that case no processing of the shebang line is necessary. When using PHP, be sure to point tot php-cgi(.exe) and not the php(.exe) executable, as the latter is a stand alone interpreter which doesn't interface over CGI with CivetWeb. +| **`cgi_pattern`** | `**.cgi$|**.pl$|**.php$` | All files that match `cgi_pattern` are treated as CGI files. The default pattern allows CGI files to be anywhere. To restrict CGIs to a certain directory, use `/path/to/cgi-bin/**.cgi` as a pattern. Note that the full path of the local file is matched against the pattern, not the URI provided in the client request.| +|**`put_delete_auth_file`**| *empty* | The option `put_delete_auth_file` defines the password file to be used for PUT and DELETE requests. Without a password file it is not possible to put new files to the server, or to delete existing ones. This only applies to direct HTTP requests which use the PUT and DELETE methods without server side scripting. PUT and DELETE requests might still be handled by Lua scripts and CGI pages. | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`struct mg_context *`| A pointer to a context structure when successful, or NULL in case of failure | + +### Description + +The function `mg_start()` is the only function needed to call to initialize the webserver. After the function returns and a pointer to a context structure is provided, it is guaranteed that the server has started and is listening on the designated ports. In case of failure a NULL pointer is returned. The behaviour of the web server is controlled by a list of callback functions and a list of options. The callback functions can do application specific processing of events which are encountered by the webserver. If a specific callback function is set to NULL, the webserver uses their default callback routine. The options list controls how the webserver should be started and contains settings for for example the ports to listen on, the maximum number of threads created to handle requests in parallel and if settings for SSL encryption. + +As a side effect on Unix systems, SIGCHLD and SIGPIPE signals will be ignored. If custom processing is needed for these signals, signal handlers must be setup after the call to `mg_start()` has completed. + +### See Also + +* [`struct mg_callbacks;`](mg_callbacks.md) +* [`mg_stop();`](mg_stop.md) diff --git a/ceph/src/civetweb/docs/api/mg_start_thread.md b/ceph/src/civetweb/docs/api/mg_start_thread.md new file mode 100644 index 000000000..e81722650 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_start_thread.md @@ -0,0 +1,26 @@ +# Civetweb API Reference + +### `mg_start_thread( func, cbdata );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`func`**|`mg_thread_func_t`|Function to start as a separate thread| +|**`cbdata`**|`void *`|User defined data to be passed to the thread as parameter| + +`void mg_thread_func_t( void *cbdata );` + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Success or error code| + +### Description + +The function `mg_start_thread()` is a convenience function to create a detached thread. The function returns **0** when successful and another value if an error occured. A pointer to user supplied data can be passed which is then passed further on to the thread function as parameter. + +### See Also + +* [`mg_start();`](mg_start.md) diff --git a/ceph/src/civetweb/docs/api/mg_stop.md b/ceph/src/civetweb/docs/api/mg_stop.md new file mode 100644 index 000000000..ea0d24666 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_stop.md @@ -0,0 +1,22 @@ +# Civetweb API Reference + +### `mg_stop( ctx );` + +#### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|**`struct mg_context *`**| A pointer to the current webserver context | + +### Return Value + +*none* + +### Description + +The function `mg_stop()` is used to stop and cleanup a running webserver. A pointer to the context of the running webserver is provided as a parameter. The execution of this function may take some time because it waits until all threads have stopped and returns all memory to the heap. After the function returns, the location the context pointer points to is invalid. The function does not return a return value and it is therefore not possible to know if stopping the webserver succeeded or not. + +### See Also + +* [`mg_start();`](mg_start.md) +* [`mg_start_thread();`](mg_start_thread.md) diff --git a/ceph/src/civetweb/docs/api/mg_store_body.md b/ceph/src/civetweb/docs/api/mg_store_body.md new file mode 100644 index 000000000..4cde44a92 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_store_body.md @@ -0,0 +1,24 @@ +# Civetweb API Reference + +### `mg_store_body( conn, path );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|connection on which to read the data| +|**`path`**|`const char *`|file to store the request body| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`long long`|Number of bytes written to the file, or an error code| + +### Description + +The function `mg_store_body()` stores the body of an incoming request to a data file. The function returns the number of bytes stored in the file, or a negative value to indicate an error. + +### See Also + +* [`mg_read();`](mg_read.md) diff --git a/ceph/src/civetweb/docs/api/mg_strcasecmp.md b/ceph/src/civetweb/docs/api/mg_strcasecmp.md new file mode 100644 index 000000000..cba6b922b --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_strcasecmp.md @@ -0,0 +1,24 @@ +# Civetweb API Reference + +### `mg_strcasecmp( s1, s2 );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`s1`**|`const char *`|First string to compare| +|**`s2`**|`const char *`|Second string to compare| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Integer value with the result of the comparison| + +### Description + +The function `mg_strcasecmp()` is a helper function to compare two strings. The comparison is case insensitive. The return value is **0** if both strings are equal, less then zero if the first string is less than the second in a lexical comparison, and greater than zero if the first string is greater than the second. + +### See Also + +* [`mg_strncasecmp();`](mg_strncasecmp.md) diff --git a/ceph/src/civetweb/docs/api/mg_strncasecmp.md b/ceph/src/civetweb/docs/api/mg_strncasecmp.md new file mode 100644 index 000000000..b4affd66b --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_strncasecmp.md @@ -0,0 +1,25 @@ +# Civetweb API Reference + +### `mg_strncasecmp( s1, s2, len );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`s1`**|`const char *`|First string in the comparison| +|**`s2`**|`const char *`|Second string in the comparison| +|**`len`**|`size_t`|The maximum number of characters to compare| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|The result of the comparison| + +### Description + +The function `mg_strncasecmp()` is a helper function to compare two strings. The comparison is case insensitive and only a limited number of characters are compared. This limit is provided as third parameter in the function call. The return value is **0** if both strings are equal, less then zero if the first string is less than the second in a lexical comparison, and greater than zero if the first string is greater than the second. + +### See Also + +* [`mg_strcasecmp();`](mg_strcasecmp.md) diff --git a/ceph/src/civetweb/docs/api/mg_unlock_connection.md b/ceph/src/civetweb/docs/api/mg_unlock_connection.md new file mode 100644 index 000000000..b74138fde --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_unlock_connection.md @@ -0,0 +1,27 @@ +# Civetweb API Reference + +### `mg_unlock_connection( conn );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|Connection to remove the lock from| + +### Return Value + +*none* + +### Description + +The function `mg_unlock_connection()` removes the lock on a connection which was previously set with a call to [`mg_lock_connection()`](mg_lock_connection.md). Locking may be necessary when using [`mg_write()`](mg_write.md) or [`mg_printf()`](mg_printf.md) on websocket connections to prevent data corruption. + +### See Also + +* [`mg_lock_connection();`](mg_lock_connection.md) +* [`mg_lock_context();`](mg_lock_context.md) +* [`mg_printf();`](mg_printf.md) +* [`mg_unlock_context();`](mg_unlock_context.md) +* [`mg_websocket_client_write();`](mg_websocket_client_write.md) +* [`mg_websocket_write();`](mg_websocket_write.md) +* [`mg_write();`](mg_write.md) diff --git a/ceph/src/civetweb/docs/api/mg_unlock_context.md b/ceph/src/civetweb/docs/api/mg_unlock_context.md new file mode 100644 index 000000000..a630acd7e --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_unlock_context.md @@ -0,0 +1,23 @@ +# Civetweb API Reference + +### `mg_unlock_context( ctx );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`ctx`**|`struct mg_context *`|The context to remove the lock from| + +### Return Value + +*none* + +### Description + +The function `mg_unlock_contect()` removes a lock put previously on a context with a call to [`mg_lock_context()`](mg_lock_context.md). Locking a context may be necessary when accessing shared resources. + +### See Also + +* [`mg_lock_connection();`](mg_lock_connection.md) +* [`mg_lock_context();`](mg_lock_context.md) +* [`mg_unlock_connection();`](mg_unlock_connection.md) diff --git a/ceph/src/civetweb/docs/api/mg_upload.md b/ceph/src/civetweb/docs/api/mg_upload.md new file mode 100644 index 000000000..de7f1c8dd --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_upload.md @@ -0,0 +1,22 @@ +# Civetweb API Reference + +### ~~`mg_upload( conn, destination_dir );`~~ + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|Connection on which files to upload| +|**`destination_dir`**|`const char *`|The destination directory to upload to| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Success or error code| + +### Description + +The function `mg_upload()` is deprecated and may be removed from future releases. Use of this function is therefore highly discouraged. + +### See Also diff --git a/ceph/src/civetweb/docs/api/mg_url_decode.md b/ceph/src/civetweb/docs/api/mg_url_decode.md new file mode 100644 index 000000000..679408848 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_url_decode.md @@ -0,0 +1,27 @@ +# Civetweb API Reference + +### `mg_url_decode( src, src_len, dst, dst_len, is_form_url_encoded );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`src`**|`const char *`|Source data to convert| +|**`src_len`**|`int`|Length of the source buffer| +|**`dst`**|`char *`|Destination buffer to store the result| +|**`dst_len`**|`int`|Length of the destination buffer| +|**`is_form_url_encoded`**|`int`|Not equal zero when form decoding must be used| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|The number of bytes stored in the destination buffer, or **-1** if the buffer doesn't exist or is too small| + +### Description + +The function `mg_url_decode()` Decodes a in input buffer. Both normal URIs and form URIs can be decoded. In the latter case the space character is converted to a `+` as defined in [RFC 1866](http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt) in section 8.2.1. + +### See Also + +* [`mg_url_encode();`](mg_url_encode.md) diff --git a/ceph/src/civetweb/docs/api/mg_url_encode.md b/ceph/src/civetweb/docs/api/mg_url_encode.md new file mode 100644 index 000000000..465af1226 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_url_encode.md @@ -0,0 +1,25 @@ +# Civetweb API Reference + +### `mg_url_encode( src, dst, des_len );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`src`**|`const char *`|Input string to encode| +|**`dst`**|`char *`|Destination buffer to store the encoded result| +|**`dst_len`**|`size_t`|Length of the destination buffer including the terminating NUL| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|The number of characters written in the destination buffer| + +### Description + +The function `mg_url_encode()` encodes a in input buffer. Both normal URIs and form URIs can be encoded. In the latter case the space character is converted to a `+` as defined in [RFC 1866](http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt) in section 8.2.1. + +### See Also + +* [`mg_url_decode();`](mg_url_decode.md) diff --git a/ceph/src/civetweb/docs/api/mg_version.md b/ceph/src/civetweb/docs/api/mg_version.md new file mode 100644 index 000000000..a31128b52 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_version.md @@ -0,0 +1,19 @@ +# Civetweb API Reference + +### `mg_version();` + +### Parameters + +*none* + +### Return Value + +| Type | Description | +| :--- | :--- | +|`const char *`| A pointer to a text with the current CivetWeb version | + +### Description + +The function `mg_version()` can be used to return the current CivetWeb version. The function returns a pointer to a string with the current major and minor version number separated with a dot, for example "1.9". + +### See Also diff --git a/ceph/src/civetweb/docs/api/mg_websocket_client_write.md b/ceph/src/civetweb/docs/api/mg_websocket_client_write.md new file mode 100644 index 000000000..f792f4c7a --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_websocket_client_write.md @@ -0,0 +1,32 @@ +# Civetweb API Reference + +### `mg_websocket_client_write( conn, opcode, data, data_len );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|Connection on which to send data| +|**`opcode`**|`int`|Opcode| +|**`data const`**|`char *`|The data to be written| +|**`data_len`**|`size_t`|Length of the data buffer| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Number of bytes written or an error code| + +### Description + +The function `mg_websocket_client_write()` sends data to a websocket server wrapped in a masked websocket frame. The function issues calls to [`mg_lock_connection()`](mg_lock_connection.md) and [`mg_unlock_connection()`](mg_unlock_connection.md) to ensure that the transmission is not interrupted. Interruption can happen the the application is proactively communicating and responding to a request simultaneously. This function is available only, if Civetweb is compiled with the option `-DUSE_WEBSOCKET`. + +The return value is the number of bytes written on success, **0** when the connection has been closed and **-1** if an error occured. + +### See Also + +* [`mg_lock_connection();`](mg_lock_connection.md) +* [`mg_printf();`](mg_printf.md) +* [`mg_unlock_connection();`](mg_unlock_connection.md) +* [`mg_websocket_write();`](mg_websocket_write.md) +* [`mg_write();`](mg_write.md) diff --git a/ceph/src/civetweb/docs/api/mg_websocket_write.md b/ceph/src/civetweb/docs/api/mg_websocket_write.md new file mode 100644 index 000000000..3c7eadc77 --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_websocket_write.md @@ -0,0 +1,34 @@ +# Civetweb API Reference + +### `mg_websocket_write( conn, opcode, data, data_len );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`|Connection on which the data must be written| +|**`opcode`**|`int`|Opcode| +|**`data`**|`const char *`|Data to be written to the client| +|**`data_len`**|`size_t`|Length of the data| + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`|Number of bytes written or an error code| + +### Description + +The function `mg_websocket_write()` sends data to a websocket client wrapped in a websocket frame. The function issues calls to [`mg_lock_connection()`](mg_lock_connection.md) and [`mg_unlock_connection()`](mg_unlock_connection.md) to ensure that the transmission is not interrupted. Data corruption can otherwise happen if the application is proactively communicating and responding to a request simultaneously. + +The function is available only when Civetweb is compiled with the `-DUSE_WEBSOCKET` option. + +The function returns the number of bytes written, **0** when the connection has been closed and **-1** if an error occurred. + +### See Also + +* [`mg_lock_connection();`](mg_lock_connection.md) +* [`mg_printf();`](mg_printf.md) +* [`mg_unlock_connection();`](mg_unlock_connection.md) +* [`mg_websocket_client_write();`](mg_websocket_client_write.md) +* [`mg_write();`](mg_write.md) diff --git a/ceph/src/civetweb/docs/api/mg_write.md b/ceph/src/civetweb/docs/api/mg_write.md new file mode 100644 index 000000000..d501857bb --- /dev/null +++ b/ceph/src/civetweb/docs/api/mg_write.md @@ -0,0 +1,29 @@ +# Civetweb API Reference + +### `mg_write( conn, buf, len );` + +### Parameters + +| Parameter | Type | Description | +| :--- | :--- | :--- | +|**`conn`**|`struct mg_connection *`| A pointer to the connection to be used to send data | +|**`buf`**|`const void *`| A pointer to the blob of information to be sent | +|**`len`**|`size_t`| The amount of bytes to be sent | + +### Return Value + +| Type | Description | +| :--- | :--- | +|`int`| An integer indicating the amount of bytes sent, or failure | + +### Description + +The function `mg_write()` can be used to send a blob of arbitrary data over a connection. The size of the data is provided as a parameter. The only length limitation on this function is `MAX_INT`, because the return value of this function will turn negative with larger blocks of data, although they may have been sent correctly. The function returns the amount of bytes sent in case of success, the value **0** when the connection has been closed, and **-1** in case of an error. + +### See Also + +* [`mg_lock_connection();`](mg_lock_connection.md) +* [`mg_printf();`](mg_print.md) +* [`mg_unlock_connection();`](mg_unlock_connection.md) +* [`mg_websocket_client_write();`](mg_websocket_client_write.md) +* [`mg_websocket_write();`](mg_websocket_write.md) diff --git a/ceph/src/civetweb/examples/README.md b/ceph/src/civetweb/examples/README.md new file mode 100644 index 000000000..cf5495977 --- /dev/null +++ b/ceph/src/civetweb/examples/README.md @@ -0,0 +1,13 @@ + +Examples +===== + +Two examples show how to embed civetweb into a C ([embedded_c](https://github.com/civetweb/civetweb/tree/master/examples/embedded_c)) or a C++ ([embedded_cpp](https://github.com/civetweb/civetweb/tree/master/examples/embedded_cpp)) application. +The C++ wrapper only offers a subset of the full C API, thus the C example is more complete than the C++ example. These examples were not designed with security in mind, but to show how the API can be used in principle. For more information, see the [documentation](https://github.com/civetweb/civetweb/tree/master/docs). Some examples can also be found in the [test](https://github.com/civetweb/civetweb/tree/master/test) folder (but they are less documented and adapted to the needs of the test framework). + +In addition, there is one example how to configure a HTTPS server, to comply with modern security standards ([https](https://github.com/civetweb/civetweb/tree/master/examples/https)). It does not hold any source, but only a configuration file and some documentation how to use it. + +Some no longer maintained examples can be found in the ["obsolete"](https://github.com/civetweb/civetweb/tree/master/examples/_obsolete) folder. It is not guaranteed that they work in the current version - they are kept for reference, but might be removed in the future. + +All examples are subject to the MIT license (unless noted otherwise) - they come without warranty of any kind. + diff --git a/ceph/src/civetweb/examples/chat/Makefile b/ceph/src/civetweb/examples/_obsolete/chat/Makefile similarity index 100% rename from ceph/src/civetweb/examples/chat/Makefile rename to ceph/src/civetweb/examples/_obsolete/chat/Makefile diff --git a/ceph/src/civetweb/examples/chat/chat.c b/ceph/src/civetweb/examples/_obsolete/chat/chat.c similarity index 100% rename from ceph/src/civetweb/examples/chat/chat.c rename to ceph/src/civetweb/examples/_obsolete/chat/chat.c diff --git a/ceph/src/civetweb/examples/docroot/favicon.ico b/ceph/src/civetweb/examples/_obsolete/docroot/favicon.ico similarity index 100% rename from ceph/src/civetweb/examples/docroot/favicon.ico rename to ceph/src/civetweb/examples/_obsolete/docroot/favicon.ico diff --git a/ceph/src/civetweb/examples/docroot/index.html b/ceph/src/civetweb/examples/_obsolete/docroot/index.html similarity index 100% rename from ceph/src/civetweb/examples/docroot/index.html rename to ceph/src/civetweb/examples/_obsolete/docroot/index.html diff --git a/ceph/src/civetweb/examples/docroot/jquery.js b/ceph/src/civetweb/examples/_obsolete/docroot/jquery.js similarity index 100% rename from ceph/src/civetweb/examples/docroot/jquery.js rename to ceph/src/civetweb/examples/_obsolete/docroot/jquery.js diff --git a/ceph/src/civetweb/examples/docroot/login.html b/ceph/src/civetweb/examples/_obsolete/docroot/login.html similarity index 100% rename from ceph/src/civetweb/examples/docroot/login.html rename to ceph/src/civetweb/examples/_obsolete/docroot/login.html diff --git a/ceph/src/civetweb/examples/docroot/logo.png b/ceph/src/civetweb/examples/_obsolete/docroot/logo.png similarity index 100% rename from ceph/src/civetweb/examples/docroot/logo.png rename to ceph/src/civetweb/examples/_obsolete/docroot/logo.png diff --git a/ceph/src/civetweb/examples/docroot/main.js b/ceph/src/civetweb/examples/_obsolete/docroot/main.js similarity index 100% rename from ceph/src/civetweb/examples/docroot/main.js rename to ceph/src/civetweb/examples/_obsolete/docroot/main.js diff --git a/ceph/src/civetweb/examples/docroot/prime_numbers.lp b/ceph/src/civetweb/examples/_obsolete/docroot/prime_numbers.lp similarity index 100% rename from ceph/src/civetweb/examples/docroot/prime_numbers.lp rename to ceph/src/civetweb/examples/_obsolete/docroot/prime_numbers.lp diff --git a/ceph/src/civetweb/examples/docroot/style.css b/ceph/src/civetweb/examples/_obsolete/docroot/style.css similarity index 100% rename from ceph/src/civetweb/examples/docroot/style.css rename to ceph/src/civetweb/examples/_obsolete/docroot/style.css diff --git a/ceph/src/civetweb/examples/hello/Makefile b/ceph/src/civetweb/examples/_obsolete/hello/Makefile similarity index 100% rename from ceph/src/civetweb/examples/hello/Makefile rename to ceph/src/civetweb/examples/_obsolete/hello/Makefile diff --git a/ceph/src/civetweb/examples/hello/hello.c b/ceph/src/civetweb/examples/_obsolete/hello/hello.c similarity index 100% rename from ceph/src/civetweb/examples/hello/hello.c rename to ceph/src/civetweb/examples/_obsolete/hello/hello.c diff --git a/ceph/src/civetweb/examples/lua/lua_dll.c b/ceph/src/civetweb/examples/_obsolete/lua/lua_dll.c similarity index 100% rename from ceph/src/civetweb/examples/lua/lua_dll.c rename to ceph/src/civetweb/examples/_obsolete/lua/lua_dll.c diff --git a/ceph/src/civetweb/examples/post/Makefile b/ceph/src/civetweb/examples/_obsolete/post/Makefile similarity index 100% rename from ceph/src/civetweb/examples/post/Makefile rename to ceph/src/civetweb/examples/_obsolete/post/Makefile diff --git a/ceph/src/civetweb/examples/post/post.c b/ceph/src/civetweb/examples/_obsolete/post/post.c similarity index 100% rename from ceph/src/civetweb/examples/post/post.c rename to ceph/src/civetweb/examples/_obsolete/post/post.c diff --git a/ceph/src/civetweb/examples/upload/Makefile b/ceph/src/civetweb/examples/_obsolete/upload/Makefile similarity index 100% rename from ceph/src/civetweb/examples/upload/Makefile rename to ceph/src/civetweb/examples/_obsolete/upload/Makefile diff --git a/ceph/src/civetweb/examples/upload/upload.c b/ceph/src/civetweb/examples/_obsolete/upload/upload.c similarity index 100% rename from ceph/src/civetweb/examples/upload/upload.c rename to ceph/src/civetweb/examples/_obsolete/upload/upload.c diff --git a/ceph/src/civetweb/examples/websocket/Makefile b/ceph/src/civetweb/examples/_obsolete/websocket/Makefile similarity index 100% rename from ceph/src/civetweb/examples/websocket/Makefile rename to ceph/src/civetweb/examples/_obsolete/websocket/Makefile diff --git a/ceph/src/civetweb/examples/websocket/WebSockCallbacks.c b/ceph/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.c similarity index 99% rename from ceph/src/civetweb/examples/websocket/WebSockCallbacks.c rename to ceph/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.c index b31bc956b..bb81fb0cc 100644 --- a/ceph/src/civetweb/examples/websocket/WebSockCallbacks.c +++ b/ceph/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.c @@ -10,7 +10,7 @@ #include "WebSockCallbacks.h" #ifdef _WIN32 -#include +#include #define mg_sleep(x) Sleep(x) #else #include diff --git a/ceph/src/civetweb/examples/websocket/WebSockCallbacks.h b/ceph/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.h similarity index 100% rename from ceph/src/civetweb/examples/websocket/WebSockCallbacks.h rename to ceph/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.h diff --git a/ceph/src/civetweb/examples/websocket/websock.htm b/ceph/src/civetweb/examples/_obsolete/websocket/websock.htm similarity index 100% rename from ceph/src/civetweb/examples/websocket/websock.htm rename to ceph/src/civetweb/examples/_obsolete/websocket/websock.htm diff --git a/ceph/src/civetweb/examples/websocket/websocket.c b/ceph/src/civetweb/examples/_obsolete/websocket/websocket.c similarity index 100% rename from ceph/src/civetweb/examples/websocket/websocket.c rename to ceph/src/civetweb/examples/_obsolete/websocket/websocket.c diff --git a/ceph/src/civetweb/examples/websocket_client/Makefile b/ceph/src/civetweb/examples/_obsolete/websocket_client/Makefile similarity index 100% rename from ceph/src/civetweb/examples/websocket_client/Makefile rename to ceph/src/civetweb/examples/_obsolete/websocket_client/Makefile diff --git a/ceph/src/civetweb/examples/websocket_client/ssl/server.crt b/ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.crt similarity index 100% rename from ceph/src/civetweb/examples/websocket_client/ssl/server.crt rename to ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.crt diff --git a/ceph/src/civetweb/examples/websocket_client/ssl/server.csr b/ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.csr similarity index 100% rename from ceph/src/civetweb/examples/websocket_client/ssl/server.csr rename to ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.csr diff --git a/ceph/src/civetweb/examples/websocket_client/ssl/server.key b/ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key similarity index 100% rename from ceph/src/civetweb/examples/websocket_client/ssl/server.key rename to ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key diff --git a/ceph/src/civetweb/examples/websocket_client/ssl/server.key.orig b/ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key.orig similarity index 100% rename from ceph/src/civetweb/examples/websocket_client/ssl/server.key.orig rename to ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key.orig diff --git a/ceph/src/civetweb/examples/websocket_client/ssl/server.pem b/ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.pem similarity index 100% rename from ceph/src/civetweb/examples/websocket_client/ssl/server.pem rename to ceph/src/civetweb/examples/_obsolete/websocket_client/ssl/server.pem diff --git a/ceph/src/civetweb/examples/websocket_client/websocket_client.c b/ceph/src/civetweb/examples/_obsolete/websocket_client/websocket_client.c similarity index 99% rename from ceph/src/civetweb/examples/websocket_client/websocket_client.c rename to ceph/src/civetweb/examples/_obsolete/websocket_client/websocket_client.c index c7bef6259..158ad7d85 100644 --- a/ceph/src/civetweb/examples/websocket_client/websocket_client.c +++ b/ceph/src/civetweb/examples/_obsolete/websocket_client/websocket_client.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014-2015 the Civetweb developers +* Copyright (c) 2014-2016 the Civetweb developers * Copyright (c) 2014 Jordan Shelley * https://github.com/jshelley * License http://opensource.org/licenses/mit-license.php MIT License @@ -12,7 +12,7 @@ // Simple example program on how to use websocket client embedded C interface. #ifdef _WIN32 -#include +#include #define sleep(x) Sleep(1000 * (x)) #else #include diff --git a/ceph/src/civetweb/examples/ws_server/Makefile b/ceph/src/civetweb/examples/_obsolete/ws_server/Makefile similarity index 100% rename from ceph/src/civetweb/examples/ws_server/Makefile rename to ceph/src/civetweb/examples/_obsolete/ws_server/Makefile diff --git a/ceph/src/civetweb/examples/ws_server/docroot/index.html b/ceph/src/civetweb/examples/_obsolete/ws_server/docroot/index.html similarity index 100% rename from ceph/src/civetweb/examples/ws_server/docroot/index.html rename to ceph/src/civetweb/examples/_obsolete/ws_server/docroot/index.html diff --git a/ceph/src/civetweb/examples/ws_server/ws_server.c b/ceph/src/civetweb/examples/_obsolete/ws_server/ws_server.c similarity index 100% rename from ceph/src/civetweb/examples/ws_server/ws_server.c rename to ceph/src/civetweb/examples/_obsolete/ws_server/ws_server.c diff --git a/ceph/src/civetweb/examples/embedded_c/Makefile b/ceph/src/civetweb/examples/embedded_c/Makefile index 56db9d612..93d6379db 100644 --- a/ceph/src/civetweb/examples/embedded_c/Makefile +++ b/ceph/src/civetweb/examples/embedded_c/Makefile @@ -24,13 +24,14 @@ endif all: $(PROG) $(PROG): $(CIVETWEB_LIB) $(SRC) - $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS) + $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS) -lcrypto -lssl -DUSE_SSL_DH=1 $(CIVETWEB_LIB): - $(MAKE) -C $(TOP) WITH_IPV6=1 WITH_WEBSOCKET=1 clean lib + $(MAKE) -C $(TOP) WITH_IPV6=1 WITH_WEBSOCKET=1 COPT='-DNO_SSL_DL=1' clean lib cp $(TOP)/$(CIVETWEB_LIB) . clean: rm -f $(CIVETWEB_LIB) $(PROG) .PHONY: all clean + diff --git a/ceph/src/civetweb/examples/embedded_c/embedded_c.c b/ceph/src/civetweb/examples/embedded_c/embedded_c.c index 33511ce85..34a361e85 100644 --- a/ceph/src/civetweb/examples/embedded_c/embedded_c.c +++ b/ceph/src/civetweb/examples/embedded_c/embedded_c.c @@ -1,12 +1,12 @@ /* -* Copyright (c) 2013-2016 the CivetWeb developers +* Copyright (c) 2013-2017 the CivetWeb developers * Copyright (c) 2013 No Face Press, LLC * License http://opensource.org/licenses/mit-license.php MIT License */ /* Simple example program on how to use CivetWeb embedded into a C program. */ #ifdef _WIN32 -#include +#include #else #include #endif @@ -21,15 +21,15 @@ #define DOCUMENT_ROOT "." #ifdef NO_SSL #ifdef USE_IPV6 -#define PORT "[::]:8888" +#define PORT "[::]:8888,8884" #else -#define PORT "8888" +#define PORT "8888,8884" #endif #else #ifdef USE_IPV6 #define PORT "[::]:8888r,[::]:8843s,8884" #else -#define PORT "8888r,8843s" +#define PORT "8888r,8843s,8884" #endif #endif #define EXAMPLE_URI "/example" @@ -40,7 +40,9 @@ int exitNow = 0; int ExampleHandler(struct mg_connection *conn, void *cbdata) { - mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); mg_printf(conn, ""); mg_printf(conn, "

This is an example text from a C handler

"); mg_printf( @@ -74,12 +76,24 @@ ExampleHandler(struct mg_connection *conn, void *cbdata) mg_printf(conn, "

To see a page from the CookieHandler handler click cookie

"); + mg_printf(conn, + "

To see a page from the PostResponser handler click post response

"); + mg_printf(conn, + "

To see an example for parsing files on the fly click form (form for " + "uploading files)

"); #ifdef USE_WEBSOCKET mg_printf(conn, - "

To test websocket handler click " + "

To test the websocket handler click " "websocket

"); #endif + + mg_printf(conn, + "

To test the authentication handler click " + "auth

"); + mg_printf(conn, "

To exit click exit

", EXIT_URI); mg_printf(conn, "\n"); return 1; @@ -89,7 +103,9 @@ ExampleHandler(struct mg_connection *conn, void *cbdata) int ExitHandler(struct mg_connection *conn, void *cbdata) { - mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"); + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: " + "text/plain\r\nConnection: close\r\n\r\n"); mg_printf(conn, "Server will shut down.\n"); mg_printf(conn, "Bye!\n"); exitNow = 1; @@ -100,7 +116,9 @@ ExitHandler(struct mg_connection *conn, void *cbdata) int AHandler(struct mg_connection *conn, void *cbdata) { - mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); mg_printf(conn, ""); mg_printf(conn, "

This is the A handler!!!

"); mg_printf(conn, "\n"); @@ -111,7 +129,9 @@ AHandler(struct mg_connection *conn, void *cbdata) int ABHandler(struct mg_connection *conn, void *cbdata) { - mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); mg_printf(conn, ""); mg_printf(conn, "

This is the AB handler!!!

"); mg_printf(conn, "\n"); @@ -125,10 +145,12 @@ BXHandler(struct mg_connection *conn, void *cbdata) /* Handler may access the request info using mg_get_request_info */ const struct mg_request_info *req_info = mg_get_request_info(conn); - mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); mg_printf(conn, ""); mg_printf(conn, "

This is the BX handler %p!!!

", cbdata); - mg_printf(conn, "

The actual uri is %s

", req_info->uri); + mg_printf(conn, "

The actual uri is %s

", req_info->local_uri); mg_printf(conn, "\n"); return 1; } @@ -140,13 +162,15 @@ FooHandler(struct mg_connection *conn, void *cbdata) /* Handler may access the request info using mg_get_request_info */ const struct mg_request_info *req_info = mg_get_request_info(conn); - mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); mg_printf(conn, ""); mg_printf(conn, "

This is the Foo handler!!!

"); mg_printf(conn, "

The request was:

%s %s HTTP/%s

", req_info->request_method, - req_info->uri, + req_info->local_uri, req_info->http_version); mg_printf(conn, "\n"); return 1; @@ -159,7 +183,9 @@ CloseHandler(struct mg_connection *conn, void *cbdata) /* Handler may access the request info using mg_get_request_info */ const struct mg_request_info *req_info = mg_get_request_info(conn); - mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); mg_printf(conn, ""); mg_printf(conn, "

This handler will close the connection in a second

"); @@ -256,7 +282,9 @@ FormHandler(struct mg_connection *conn, void *cbdata) * mg_handle_form_request. */ (void)req_info; - mg_printf(conn, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n"); + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: " + "text/plain\r\nConnection: close\r\n\r\n"); fdh.user_data = (void *)conn; /* Call the form handler */ @@ -268,6 +296,132 @@ FormHandler(struct mg_connection *conn, void *cbdata) } +int +FileUploadForm(struct mg_connection *conn, void *cbdata) +{ + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); + + mg_printf(conn, "\n"); + mg_printf(conn, "\n\n"); + mg_printf(conn, "\n"); + mg_printf(conn, "File upload\n"); + mg_printf(conn, "\n\n"); + mg_printf(conn, + "
\n", + (const char *)cbdata); + mg_printf(conn, "\n"); + mg_printf(conn, "\n"); + mg_printf(conn, "
\n\n\n"); + return 1; +} + +#define MD5_STATIC static +#include "../src/md5.inl" + +struct tfile_checksum { + char name[128]; + unsigned long long length; + md5_state_t chksum; +}; + +#define MAX_FILES (10) + +struct tfiles_checksums { + int index; + struct tfile_checksum file[MAX_FILES]; +}; + + +int +field_disp_read_on_the_fly(const char *key, + const char *filename, + char *path, + size_t pathlen, + void *user_data) +{ + struct tfiles_checksums *context = (struct tfiles_checksums *)user_data; + + (void)key; + (void)path; + (void)pathlen; + + if (context->index < MAX_FILES) { + context->index++; + strncpy(context->file[context->index - 1].name, filename, 128); + context->file[context->index - 1].name[127] = 0; + context->file[context->index - 1].length = 0; + md5_init(&(context->file[context->index - 1].chksum)); + return FORM_FIELD_STORAGE_GET; + } + return FORM_FIELD_STORAGE_ABORT; +} + + +int +field_get_checksum(const char *key, + const char *value, + size_t valuelen, + void *user_data) +{ + struct tfiles_checksums *context = (struct tfiles_checksums *)user_data; + (void)key; + + context->file[context->index - 1].length += valuelen; + md5_append(&(context->file[context->index - 1].chksum), + (const md5_byte_t *)value, + valuelen); + + return 0; +} + + +int +CheckSumHandler(struct mg_connection *conn, void *cbdata) +{ + /* Handler may access the request info using mg_get_request_info */ + const struct mg_request_info *req_info = mg_get_request_info(conn); + int i, j, ret; + struct tfiles_checksums chksums; + md5_byte_t digest[16]; + struct mg_form_data_handler fdh = {field_disp_read_on_the_fly, + field_get_checksum, + 0, + (void *)&chksums}; + + /* It would be possible to check the request info here before calling + * mg_handle_form_request. */ + (void)req_info; + + memset(&chksums, 0, sizeof(chksums)); + + mg_printf(conn, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Connection: close\r\n\r\n"); + + /* Call the form handler */ + mg_printf(conn, "File checksums:"); + ret = mg_handle_form_request(conn, &fdh); + for (i = 0; i < chksums.index; i++) { + md5_finish(&(chksums.file[i].chksum), digest); + /* Visual Studio 2010+ support llu */ + mg_printf(conn, + "\r\n%s %llu ", + chksums.file[i].name, + chksums.file[i].length); + for (j = 0; j < 16; j++) { + mg_printf(conn, "%02x", (unsigned int)digest[j]); + } + } + mg_printf(conn, "\r\n%i files\r\n", ret); + + return 1; +} + + int CookieHandler(struct mg_connection *conn, void *cbdata) { @@ -280,7 +434,7 @@ CookieHandler(struct mg_connection *conn, void *cbdata) (void)mg_get_cookie(cookie, "first", first_str, sizeof(first_str)); (void)mg_get_cookie(cookie, "count", count_str, sizeof(count_str)); - mg_printf(conn, "HTTP/1.1 200 OK\r\n"); + mg_printf(conn, "HTTP/1.1 200 OK\r\nConnection: close\r\n"); if (first_str[0] == 0) { time_t t = time(0); struct tm *ptm = localtime(&t); @@ -298,8 +452,8 @@ CookieHandler(struct mg_connection *conn, void *cbdata) mg_printf(conn, "Content-Type: text/html\r\n\r\n"); mg_printf(conn, ""); - mg_printf(conn, "

This is the CookieHandler.

", cbdata); - mg_printf(conn, "

The actual uri is %s

", req_info->uri); + mg_printf(conn, "

This is the CookieHandler.

"); + mg_printf(conn, "

The actual uri is %s

", req_info->local_uri); if (first_str[0] == 0) { mg_printf(conn, "

This is the first time, you opened this page

"); @@ -313,10 +467,138 @@ CookieHandler(struct mg_connection *conn, void *cbdata) } +int +PostResponser(struct mg_connection *conn, void *cbdata) +{ + long long r_total = 0; + int r, s; + + char buf[2048]; + + const struct mg_request_info *ri = mg_get_request_info(conn); + + if (strcmp(ri->request_method, "POST")) { + char buf[1024]; + int ret = mg_get_request_link(conn, buf, sizeof(buf)); + + mg_printf(conn, + "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n"); + mg_printf(conn, "Content-Type: text/plain\r\n\r\n"); + mg_printf(conn, + "%s method not allowed in the POST handler\n", + ri->request_method); + if (ret >= 0) { + mg_printf(conn, + "use a web tool to send a POST request to %s\n", + buf); + } + return 1; + } + + if (ri->content_length >= 0) { + /* We know the content length in advance */ + } else { + /* We must read until we find the end (chunked encoding + * or connection close), indicated my mg_read returning 0 */ + } + + mg_printf(conn, + "HTTP/1.1 200 OK\r\nConnection: " + "close\r\nTransfer-Encoding: chunked\r\n"); + mg_printf(conn, "Content-Type: text/plain\r\n\r\n"); + + r = mg_read(conn, buf, sizeof(buf)); + while (r > 0) { + r_total += r; + s = mg_send_chunk(conn, buf, r); + if (r != s) { + /* Send error */ + break; + } + r = mg_read(conn, buf, sizeof(buf)); + } + mg_printf(conn, "0\r\n"); + + return 1; +} + + +int +AuthStartHandler(struct mg_connection *conn, void *cbdata) +{ + static unsigned long long firstload = 0; + const char *passfile = "password_example_file.txt"; + const char *realm = "password_example"; + const char *user = "user"; + char passwd[64]; + + if (firstload == 0) { + + /* Set a random password (4 digit number - bad idea from a security + * point of view, but this is an API demo, not a security tutorial), + * and store it in some directory within the document root (extremely + * bad idea, but this is still not a security tutorial). + * The reason we create a new password every time the server starts + * is just for demonstration - we don't want the browser to store the + * password, so when we repeat the test we start with a new password. + */ + firstload = (unsigned long long)time(NULL); + sprintf(passwd, "%04u", (unsigned int)(firstload % 10000)); + mg_modify_passwords_file(passfile, realm, user, passwd); + + /* Just tell the user the new password generated for this test. */ + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); + + mg_printf(conn, "\n"); + mg_printf(conn, "\n\n"); + mg_printf(conn, "\n"); + mg_printf(conn, "Auth handlerexample\n"); + mg_printf(conn, "\n"); + + mg_printf(conn, "\n"); + mg_printf(conn, + "

The first time you visit this page, it's free!

\n"); + mg_printf(conn, + "

Next time, use username \"%s\" and password \"%s\"

\n", + user, + passwd); + mg_printf(conn, "\n\n"); + + return 1; + } + + if (mg_check_digest_access_authentication(conn, realm, passfile) <= 0) { + /* No valid authorization */ + mg_send_digest_access_authentication_request(conn, realm); + return 1; + } + + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); + + mg_printf(conn, "\n"); + mg_printf(conn, "\n\n"); + mg_printf(conn, "\n"); + mg_printf(conn, "Auth handlerexample\n"); + mg_printf(conn, "\n"); + + mg_printf(conn, "\n"); + mg_printf(conn, "

This is the password protected contents

\n"); + mg_printf(conn, "\n\n"); + + return 1; +} + + int WebSocketStartHandler(struct mg_connection *conn, void *cbdata) { - mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); + mg_printf(conn, + "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " + "close\r\n\r\n"); mg_printf(conn, "\n"); mg_printf(conn, "\n\n"); @@ -437,7 +719,31 @@ WebsocketDataHandler(struct mg_connection *conn, ASSERT(client->conn == conn); ASSERT(client->state >= 1); - fprintf(stdout, "Websocket got data:\r\n"); + fprintf(stdout, "Websocket got %lu bytes of ", (unsigned long)len); + switch (((unsigned char)bits) & 0x0F) { + case WEBSOCKET_OPCODE_CONTINUATION: + fprintf(stdout, "continuation"); + break; + case WEBSOCKET_OPCODE_TEXT: + fprintf(stdout, "text"); + break; + case WEBSOCKET_OPCODE_BINARY: + fprintf(stdout, "binary"); + break; + case WEBSOCKET_OPCODE_CONNECTION_CLOSE: + fprintf(stdout, "close"); + break; + case WEBSOCKET_OPCODE_PING: + fprintf(stdout, "ping"); + break; + case WEBSOCKET_OPCODE_PONG: + fprintf(stdout, "pong"); + break; + default: + fprintf(stdout, "unknown(%1xh)", ((unsigned char)bits) & 0x0F); + break; + } + fprintf(stdout, " data:\r\n"); fwrite(data, len, 1, stdout); fprintf(stdout, "\r\n\r\n"); @@ -486,26 +792,129 @@ InformWebsockets(struct mg_context *ctx) #endif +#ifdef USE_SSL_DH +#include "openssl/ssl.h" +#include "openssl/dh.h" +#include "openssl/ec.h" +#include "openssl/evp.h" +#include "openssl/ecdsa.h" + +DH * +get_dh2236() +{ + static unsigned char dh2236_p[] = { + 0x0E, 0x97, 0x6E, 0x6A, 0x88, 0x84, 0xD2, 0xD7, 0x55, 0x6A, 0x17, 0xB7, + 0x81, 0x9A, 0x98, 0xBC, 0x7E, 0xD1, 0x6A, 0x44, 0xB1, 0x18, 0xE6, 0x25, + 0x3A, 0x62, 0x35, 0xF0, 0x41, 0x91, 0xE2, 0x16, 0x43, 0x9D, 0x8F, 0x7D, + 0x5D, 0xDA, 0x85, 0x47, 0x25, 0xC4, 0xBA, 0x68, 0x0A, 0x87, 0xDC, 0x2C, + 0x33, 0xF9, 0x75, 0x65, 0x17, 0xCB, 0x8B, 0x80, 0xFE, 0xE0, 0xA8, 0xAF, + 0xC7, 0x9E, 0x82, 0xBE, 0x6F, 0x1F, 0x00, 0x04, 0xBD, 0x69, 0x50, 0x8D, + 0x9C, 0x3C, 0x41, 0x69, 0x21, 0x4E, 0x86, 0xC8, 0x2B, 0xCC, 0x07, 0x4D, + 0xCF, 0xE4, 0xA2, 0x90, 0x8F, 0x66, 0xA9, 0xEF, 0xF7, 0xFC, 0x6F, 0x5F, + 0x06, 0x22, 0x00, 0xCB, 0xCB, 0xC3, 0x98, 0x3F, 0x06, 0xB9, 0xEC, 0x48, + 0x3B, 0x70, 0x6E, 0x94, 0xE9, 0x16, 0xE1, 0xB7, 0x63, 0x2E, 0xAB, 0xB2, + 0xF3, 0x84, 0xB5, 0x3D, 0xD7, 0x74, 0xF1, 0x6A, 0xD1, 0xEF, 0xE8, 0x04, + 0x18, 0x76, 0xD2, 0xD6, 0xB0, 0xB7, 0x71, 0xB6, 0x12, 0x8F, 0xD1, 0x33, + 0xAB, 0x49, 0xAB, 0x09, 0x97, 0x35, 0x9D, 0x4B, 0xBB, 0x54, 0x22, 0x6E, + 0x1A, 0x33, 0x18, 0x02, 0x8A, 0xF4, 0x7C, 0x0A, 0xCE, 0x89, 0x75, 0x2D, + 0x10, 0x68, 0x25, 0xA9, 0x6E, 0xCD, 0x97, 0x49, 0xED, 0xAE, 0xE6, 0xA7, + 0xB0, 0x07, 0x26, 0x25, 0x60, 0x15, 0x2B, 0x65, 0x88, 0x17, 0xF2, 0x5D, + 0x2C, 0xF6, 0x2A, 0x7A, 0x8C, 0xAD, 0xB6, 0x0A, 0xA2, 0x57, 0xB0, 0xC1, + 0x0E, 0x5C, 0xA8, 0xA1, 0x96, 0x58, 0x9A, 0x2B, 0xD4, 0xC0, 0x8A, 0xCF, + 0x91, 0x25, 0x94, 0xB4, 0x14, 0xA7, 0xE4, 0xE2, 0x1B, 0x64, 0x5F, 0xD2, + 0xCA, 0x70, 0x46, 0xD0, 0x2C, 0x95, 0x6B, 0x9A, 0xFB, 0x83, 0xF9, 0x76, + 0xE6, 0xD4, 0xA4, 0xA1, 0x2B, 0x2F, 0xF5, 0x1D, 0xE4, 0x06, 0xAF, 0x7D, + 0x22, 0xF3, 0x04, 0x30, 0x2E, 0x4C, 0x64, 0x12, 0x5B, 0xB0, 0x55, 0x3E, + 0xC0, 0x5E, 0x56, 0xCB, 0x99, 0xBC, 0xA8, 0xD9, 0x23, 0xF5, 0x57, 0x40, + 0xF0, 0x52, 0x85, 0x9B, + }; + static unsigned char dh2236_g[] = { + 0x02, + }; + DH *dh; + + if ((dh = DH_new()) == NULL) + return (NULL); + dh->p = BN_bin2bn(dh2236_p, sizeof(dh2236_p), NULL); + dh->g = BN_bin2bn(dh2236_g, sizeof(dh2236_g), NULL); + if ((dh->p == NULL) || (dh->g == NULL)) { + DH_free(dh); + return (NULL); + } + return (dh); +} +#endif + + +#ifndef NO_SSL +int +init_ssl(void *ssl_context, void *user_data) +{ + /* Add application specific SSL initialization */ + struct ssl_ctx_st *ctx = (struct ssl_ctx_st *)ssl_context; + +#ifdef USE_SSL_DH + /* example from https://github.com/civetweb/civetweb/issues/347 */ + DH *dh = get_dh2236(); + if (!dh) + return -1; + if (1 != SSL_CTX_set_tmp_dh(ctx, dh)) + return -1; + DH_free(dh); + + EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (!ecdh) + return -1; + if (1 != SSL_CTX_set_tmp_ecdh(ctx, ecdh)) + return -1; + EC_KEY_free(ecdh); + + printf("ECDH ciphers initialized\n"); +#endif + return 0; +} +#endif + + +int +log_message(const struct mg_connection *conn, const char *message) +{ + puts(message); + return 1; +} + + int main(int argc, char *argv[]) { - const char *options[] = {"document_root", - DOCUMENT_ROOT, - "listening_ports", - PORT, - "request_timeout_ms", - "10000", - "error_log_file", - "error.log", + const char *options[] = { + "document_root", + DOCUMENT_ROOT, + "listening_ports", + PORT, + "request_timeout_ms", + "10000", + "error_log_file", + "error.log", #ifdef USE_WEBSOCKET - "websocket_timeout_ms", - "3600000", + "websocket_timeout_ms", + "3600000", #endif #ifndef NO_SSL - "ssl_certificate", - "../../resources/cert/server.pem", + "ssl_certificate", + "../../resources/cert/server.pem", + "ssl_protocol_version", + "3", + "ssl_cipher_list", +#ifdef USE_SSL_DH + "ECDHE-RSA-AES256-GCM-SHA384:DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256", +#else + "DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256", #endif - 0}; +#endif + "enable_auth_domain_check", + "no", + 0}; struct mg_callbacks callbacks; struct mg_context *ctx; struct mg_server_ports ports[32]; @@ -544,8 +953,18 @@ main(int argc, char *argv[]) /* Start CivetWeb web server */ memset(&callbacks, 0, sizeof(callbacks)); +#ifndef NO_SSL + callbacks.init_ssl = init_ssl; +#endif + callbacks.log_message = log_message; ctx = mg_start(&callbacks, 0, options); + /* Check return value: */ + if (ctx == NULL) { + fprintf(stderr, "Cannot start CivetWeb - mg_start failed.\n"); + return EXIT_FAILURE; + } + /* Add handler EXAMPLE_URI, to explain the example */ mg_set_request_handler(ctx, EXAMPLE_URI, ExampleHandler, 0); mg_set_request_handler(ctx, EXIT_URI, ExitHandler, 0); @@ -577,12 +996,29 @@ main(int argc, char *argv[]) FormHandler, (void *)0); + /* Add a file upload handler for parsing files on the fly */ + mg_set_request_handler(ctx, + "/on_the_fly_form", + FileUploadForm, + (void *)"/on_the_fly_form.md5.callback"); + mg_set_request_handler(ctx, + "/on_the_fly_form.md5.callback", + CheckSumHandler, + (void *)0); + /* Add handler for /cookie example */ mg_set_request_handler(ctx, "/cookie", CookieHandler, 0); + /* Add handler for /postresponse example */ + mg_set_request_handler(ctx, "/postresponse", PostResponser, 0); + /* Add HTTP site to open a websocket connection */ mg_set_request_handler(ctx, "/websocket", WebSocketStartHandler, 0); + /* Add HTTP site with auth */ + mg_set_request_handler(ctx, "/auth", AuthStartHandler, 0); + + #ifdef USE_WEBSOCKET /* WS site for the websocket connection */ mg_set_websocket_handler(ctx, diff --git a/ceph/src/civetweb/examples/embedded_cpp/embedded_cpp.cpp b/ceph/src/civetweb/examples/embedded_cpp/embedded_cpp.cpp index 979004262..d45a573cf 100644 --- a/ceph/src/civetweb/examples/embedded_cpp/embedded_cpp.cpp +++ b/ceph/src/civetweb/examples/embedded_cpp/embedded_cpp.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014 the Civetweb developers +/* Copyright (c) 2013-2017 the Civetweb developers * Copyright (c) 2013 No Face Press, LLC * License http://opensource.org/licenses/mit-license.php MIT License */ @@ -6,9 +6,10 @@ // Simple example program on how to use Embedded C++ interface. #include "CivetServer.h" +#include #ifdef _WIN32 -#include +#include #else #include #endif @@ -43,6 +44,9 @@ class ExampleHandler : public CivetHandler mg_printf(conn, "

To see a page from the *.foo handler click here

\r\n"); + mg_printf(conn, + "

To see a page from the WebSocket handler click here

\r\n"); mg_printf(conn, "

To exit click here

\r\n", EXIT_URI); @@ -136,7 +140,7 @@ class FooHandler : public CivetHandler mg_printf(conn, "

The request was:

%s %s HTTP/%s

\n", req_info->request_method, - req_info->uri, + req_info->request_uri, req_info->http_version); mg_printf(conn, "\n"); @@ -161,7 +165,7 @@ class FooHandler : public CivetHandler mg_printf(conn, "

The request was:

%s %s HTTP/%s

\n", req_info->request_method, - req_info->uri, + req_info->request_uri, req_info->http_version); mg_printf(conn, "

Content Length: %li

\n", (long)tlen); mg_printf(conn, "
\n");
@@ -176,7 +180,7 @@ class FooHandler : public CivetHandler
 				break;
 			}
 			wlen = mg_write(conn, buf, (size_t)rlen);
-			if (rlen != rlen) {
+			if (wlen != rlen) {
 				break;
 			}
 			nlen += wlen;
@@ -202,9 +206,32 @@ class FooHandler : public CivetHandler
         char buf[1024];
         int fail = 0;
 
+#ifdef _WIN32
         _snprintf(buf, sizeof(buf), "D:\\somewhere\\%s\\%s", req_info->remote_user, req_info->local_uri);
-        buf[sizeof(buf)-1] = 0; /* TODO: check overflow */
-        f = fopen_recursive(buf, "wb");
+        buf[sizeof(buf)-1] = 0;
+        if (strlen(buf)>255) {
+            /* Windows will not work with path > 260 (MAX_PATH), unless we use
+             * the unicode API. However, this is just an example code: A real
+             * code will probably never store anything to D:\\somewhere and
+             * must be adapted to the specific needs anyhow. */
+            fail = 1;
+            f = NULL;
+        } else {
+            f = fopen_recursive(buf, "wb");
+        }
+#else
+        snprintf(buf, sizeof(buf), "~/somewhere/%s/%s", req_info->remote_user, req_info->local_uri);
+        buf[sizeof(buf)-1] = 0;
+        if (strlen(buf)>1020) {
+            /* The string is too long and probably truncated. Make sure an
+             * UTF-8 string is never truncated between the UTF-8 code bytes.
+             * This example code must be adapted to the specific needs. */
+            fail = 1;
+            f = NULL;
+        } else {
+            f = fopen_recursive(buf, "w");
+        }
+#endif
 
         if (!f) {
             fail = 1;
@@ -220,7 +247,7 @@ class FooHandler : public CivetHandler
                     break;
                 }
                 wlen = fwrite(buf, 1, (size_t)rlen, f);
-                if (rlen != rlen) {
+                if (wlen != rlen) {
                     fail = 1;
                     break;
                 }
@@ -234,19 +261,110 @@ class FooHandler : public CivetHandler
                 "HTTP/1.1 409 Conflict\r\n"
                 "Content-Type: text/plain\r\n"
                 "Connection: close\r\n\r\n");
-            MessageBeep(MB_ICONERROR);
         } else {
             mg_printf(conn,
                 "HTTP/1.1 201 Created\r\n"
                 "Content-Type: text/plain\r\n"
                 "Connection: close\r\n\r\n");
-            MessageBeep(MB_OK);
         }
 
         return true;
     }
 };
 
+class WsStartHandler : public CivetHandler
+{
+  public:
+	bool
+	handleGet(CivetServer *server, struct mg_connection *conn)
+	{
+
+	mg_printf(conn,
+	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+	          "close\r\n\r\n");
+
+	mg_printf(conn, "\n");
+	mg_printf(conn, "\n\n");
+	mg_printf(conn, "\n");
+	mg_printf(conn, "Embedded websocket example\n");
+
+#ifdef USE_WEBSOCKET
+	/* mg_printf(conn, "\n"); ... xhtml style */
+	mg_printf(conn, "\n");
+	mg_printf(conn, "\n\n");
+	mg_printf(
+	    conn,
+	    "
No websocket connection yet
\n"); +#else + mg_printf(conn, "\n\n"); + mg_printf(conn, "Example not compiled with USE_WEBSOCKET\n"); +#endif + mg_printf(conn, "\n\n"); + + return 1; +} +}; + + +#ifdef USE_WEBSOCKET +class WebSocketHandler : public CivetWebSocketHandler { + + virtual bool handleConnection(CivetServer *server, + const struct mg_connection *conn) { + printf("WS connected\n"); + return true; + } + + virtual void handleReadyState(CivetServer *server, + struct mg_connection *conn) { + printf("WS ready\n"); + + const char *text = "Hello from the websocket ready handler"; + mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, text, strlen(text)); + } + + virtual bool handleData(CivetServer *server, + struct mg_connection *conn, + int bits, + char *data, + size_t data_len) { + printf("WS got %lu bytes: ", (long unsigned)data_len); + fwrite(data, 1, data_len, stdout); + printf("\n"); + + mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, data, data_len); + return (data_len<4); + } + + virtual void handleClose(CivetServer *server, + const struct mg_connection *conn) { + printf("WS closed\n"); + } +}; +#endif + int main(int argc, char *argv[]) @@ -260,7 +378,7 @@ main(int argc, char *argv[]) } // CivetServer server(options); // <-- C style start - CivetServer server(cpp_options); // <-- C++ style start + CivetServer server(cpp_options); // <-- C++ style start ExampleHandler h_ex; server.addHandler(EXAMPLE_URI, h_ex); @@ -274,10 +392,29 @@ main(int argc, char *argv[]) ABHandler h_ab; server.addHandler("/a/b", h_ab); + WsStartHandler h_ws; + server.addHandler("/ws", h_ws); + +#ifdef NO_FILES + /* This handler will handle "everything else", including + * requests to files. If this handler is installed, + * NO_FILES should be set. */ FooHandler h_foo; server.addHandler("", h_foo); + printf("See a page from the \"all\" handler at http://localhost:%s/\n", PORT); +#else + FooHandler h_foo; + server.addHandler("**.foo", h_foo); printf("Browse files at http://localhost:%s/\n", PORT); +#endif + +#ifdef USE_WEBSOCKET + WebSocketHandler h_websocket; + server.addWebSocketHandler("/websocket", h_websocket); + printf("Run websocket example at http://localhost:%s/ws\n", PORT); +#endif + printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI); printf("Exit at http://localhost:%s%s\n", PORT, EXIT_URI); diff --git a/ceph/src/civetweb/examples/https/README.md b/ceph/src/civetweb/examples/https/README.md new file mode 100644 index 000000000..7b18b4724 --- /dev/null +++ b/ceph/src/civetweb/examples/https/README.md @@ -0,0 +1,15 @@ +HTTPS Server configuration example +==== + +This directory contains an example [`civetweb.conf`](civetweb.conf) configuration file for a secure HTTPS server. You can run a HTTPS server without most of the options there - only `ssl_certificate` and one port (e.g., `443s`) in `listening_ports` is required. The default settings will work, but not comply with up to date security standards. It is somewhat debatable what "up to date security" means - you can use the following web sites to run tests: + +- https://securityheaders.io +- https://www.htbridge.com/ssl +- https://www.htbridge.com/websec +- https://www.ssllabs.com/ssltest/analyze.html / https://www.qualys.com/forms/freescan/ +- probably there are some more ... let me know! + +Instructions to run the test and to adapt the configuration can be found [`civetweb.conf`](civetweb.conf). You can test this configuration directly with the standalone server, or you can take the settings and add it into your embedding code. + +Note: I do not take any warranty or liability for this configuration, or for the content of any linked web site. + diff --git a/ceph/src/civetweb/examples/https/civetweb.conf b/ceph/src/civetweb/examples/https/civetweb.conf new file mode 100644 index 000000000..cd10eddab --- /dev/null +++ b/ceph/src/civetweb/examples/https/civetweb.conf @@ -0,0 +1,86 @@ +# Instructions to run (on Linux) to reproduce test results: +# +# 1) copy civetweb executable here (examples/https directory) +# 2) sudo ./civetweb +# +# Instructions to adapt to your own server: +# +# 1) generate your own server cert +# 2) generate at least one backup server cert +# in case you want a self signed cert, you can use the script +# in resources/cert for both steps +# 3) copy the content of the *.pin files into the Public-Key-Pins +# header config (the base64 encoded certificate hash) +# 4) set the document root, and all other required http server settings +# 5) Run the tests from the three websites below. They will tell you +# also what clients are compatible with your settings. The settings +# here are very strict and lock out most older clients/browsers. +# You will find some hints for fine tuning there as well. +# 6) If you know all your clients, and give them client certificates in +# advance, you can significantly improve security by setting +# "ssl_verify_peer" to "yes" and specifying a client cert (directory) +# using "ssl_ca_file/path". This will lock out all clients without a +# proper certificate. Don't use it for your public home page, but +# consider it for your private remote access server. +# 7) run civetweb, like above - or better create your own start script +# You are welcome to share your thoughts and experience on GitHub +# (or Google groups) - see README.md in CivetWeb main directory + +# Don't run as super user, switch back to a regular user +run_as_user user + +# The standard HTTP port 80 should redirect to the standard HTTPS port 443 +listening_ports 80r,443s + +# Don't forget to set the document root and domain +#document_root tdb +#authentication_domain mydomain.com + +# Set the a certificate +ssl_certificate ../../resources/cert/server.pem + +# Require a client cert for your private server (see above) +#ssl_verify_peer yes +#ssl_ca_file ../../resources/cert/client.pem + +# Enforce TLS1.2 and some strong cipher(s) +ssl_protocol_version 4 +ssl_cipher_list ECDH+AESGCM+AES256:!aNULL:!MD5:!DSS + +# Tell all browsers to access this site only as HTTPS for the next 180 days +strict_transport_security_max_age 15552000 + +# Set some HTTP security header, see https://securityheaders.io +additional_header Content-Security-Policy: script-src 'self' +additional_header X-Frame-Options: SAMEORIGIN +additional_header X-Xss-Protection: 1; mode=block +additional_header X-Content-Type-Options: nosniff +additional_header Referrer-Policy: same-origin +additional_header Public-Key-Pins: pin-sha256="uz1UTAPen+xb+UoQqkVlEx4H653LbMjfRJcZx5OrjbI="; pin-sha256="pf3px1MBPmlTGAPoiHWqaSJ9L9Z+DKfwgsU7LfLnmsk="; max-age=7776000 +#additional_header Expect-CT: max-age=86400,report-uri="https://mydomain.com/report" + + +# Ratings from 2017-09-03 (tests performed later may require more +# strict security settings) +# +# Headers rated A+ from https://securityheaders.io/ +# +# SSL rated B from https://www.htbridge.com/ssl when using a self signed +# certificate, but no other weaknesses for modern browsers. +# Site remarks some older TLS versions and some weaker ciphers are not +# supported (but that's accessibility, not security). +# +# HTTPS rated A+ from https://www.htbridge.com/websec/ when using a self +# signed certificate, generated with make_certs.sh in resources/cert/ +# and adding the server.pin and server_bkup.pin content into the +# Public-Key-Pins header above. +# +# A rating of "T / If trust issues are ignored: A" (ignoring self-signed cert) +# from https://www.ssllabs.com/ssltest/, https://www.qualys.com/forms/freescan/ +# (Note: this test is runs with reverse DNS name, while all others use the +# IP address). +# +# Note: This settings are very strict and prevent some older but still common +# versions of major browsers to access this site. The test web sites will give +# you an overview. Test, before you use this settings. + diff --git a/ceph/src/civetweb/format.bat b/ceph/src/civetweb/format.bat old mode 100644 new mode 100755 index 35e8a626a..e1ce64094 --- a/ceph/src/civetweb/format.bat +++ b/ceph/src/civetweb/format.bat @@ -4,6 +4,7 @@ clang-format -i src/main.c clang-format -i src/CivetServer.cpp clang-format -i src/civetweb_private_lua.h clang-format -i src/md5.inl +clang-format -i src/sha1.inl clang-format -i src/mod_lua.inl clang-format -i src/mod_duktape.inl clang-format -i src/timer.inl @@ -24,6 +25,8 @@ clang-format -i test/private_exe.h clang-format -i test/private_exe.c clang-format -i test/shared.h clang-format -i test/shared.c +clang-format -i test/timertest.h +clang-format -i test/timertest.c clang-format -i test/civetweb_check.h clang-format -i test/main.c diff --git a/ceph/src/civetweb/include/CivetServer.h b/ceph/src/civetweb/include/CivetServer.h index ee15ae302..2da1096d8 100644 --- a/ceph/src/civetweb/include/CivetServer.h +++ b/ceph/src/civetweb/include/CivetServer.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014 the Civetweb developers +/* Copyright (c) 2013-2017 the Civetweb developers * Copyright (c) 2013 No Face Press, LLC * * License http://opensource.org/licenses/mit-license.php MIT License @@ -227,9 +227,11 @@ class CIVETWEB_API CivetServer * @throws CivetException */ CivetServer(const char **options, - const struct CivetCallbacks *callbacks = 0); + const struct CivetCallbacks *callbacks = 0, + const void *UserContext = 0); CivetServer(std::vector options, - const struct CivetCallbacks *callbacks = 0); + const struct CivetCallbacks *callbacks = 0, + const void *UserContext = 0); /** * Destructor @@ -531,6 +533,14 @@ class CIVETWEB_API CivetServer std::string &dst, bool append = false); + // generic user context which can be set/read, + // the server does nothing with this apart from keep it. + const void * + getUserContext() const + { + return UserContext; + } + protected: class CivetConnection { @@ -545,6 +555,10 @@ class CIVETWEB_API CivetServer struct mg_context *context; std::map connections; + // generic user context which can be set/read, + // the server does nothing with this apart from keep it. + const void *UserContext; + private: /** * requestHandler(struct mg_connection *, void *cbdata) diff --git a/ceph/src/civetweb/include/civetweb.h b/ceph/src/civetweb/include/civetweb.h index db1848991..6ddde4f2f 100644 --- a/ceph/src/civetweb/include/civetweb.h +++ b/ceph/src/civetweb/include/civetweb.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016 the Civetweb developers +/* Copyright (c) 2013-2017 the Civetweb developers * Copyright (c) 2004-2013 Sergey Lyubka * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -23,7 +23,11 @@ #ifndef CIVETWEB_HEADER_INCLUDED #define CIVETWEB_HEADER_INCLUDED -#define CIVETWEB_VERSION "1.8" +#define CIVETWEB_VERSION "1.10" +#define CIVETWEB_VERSION_MAJOR (1) +#define CIVETWEB_VERSION_MINOR (10) +#define CIVETWEB_VERSION_PATCH (0) +#define CIVETWEB_VERSION_RELEASED #ifndef CIVETWEB_API #if defined(_WIN32) @@ -49,10 +53,38 @@ extern "C" { #endif /* __cplusplus */ +/* Initialize this library. This should be called once before any other + * function from this library. This function is not guaranteed to be + * thread safe. + * Parameters: + * features: bit mask for features to be initialized. + * Return value: + * initialized features + * 0: error + */ +CIVETWEB_API unsigned mg_init_library(unsigned features); + + +/* Un-initialize this library. + * Return value: + * 0: error + */ +CIVETWEB_API unsigned mg_exit_library(void); + + struct mg_context; /* Handle for the HTTP service itself */ struct mg_connection; /* Handle for the individual connection */ +/* Maximum number of headers */ +#define MG_MAX_HEADERS (64) + +struct mg_header { + const char *name; /* HTTP header name */ + const char *value; /* HTTP header value */ +}; + + /* This structure contains information about the HTTP request. */ struct mg_request_info { const char *request_method; /* "GET", "POST", etc */ @@ -61,13 +93,15 @@ struct mg_request_info { const char *local_uri; /* URL-decoded URI (relative). Can be NULL * if the request_uri does not address a * resource at the server host. */ - const char *uri; /* Deprecated: use local_uri instead */ - const char *http_version; /* E.g. "1.0", "1.1" */ - const char *query_string; /* URL part after '?', not including '?', or - NULL */ - const char *remote_user; /* Authenticated user, or NULL if no auth - used */ - char remote_addr[48]; /* Client's IP address as a string. */ +#if defined(MG_LEGACY_INTERFACE) + const char *uri; /* Deprecated: use local_uri instead */ +#endif + const char *http_version; /* E.g. "1.0", "1.1" */ + const char *query_string; /* URL part after '?', not including '?', or + NULL */ + const char *remote_user; /* Authenticated user, or NULL if no auth + used */ + char remote_addr[48]; /* Client's IP address as a string. */ #if defined(MG_LEGACY_INTERFACE) long remote_ip; /* Client's IP address. Deprecated: use remote_addr instead @@ -82,10 +116,47 @@ struct mg_request_info { void *conn_data; /* Connection-specific user data */ int num_headers; /* Number of HTTP headers */ - struct mg_header { - const char *name; /* HTTP header name */ - const char *value; /* HTTP header value */ - } http_headers[64]; /* Maximum 64 headers */ + struct mg_header + http_headers[MG_MAX_HEADERS]; /* Allocate maximum headers */ + + struct mg_client_cert *client_cert; /* Client certificate information */ + + const char *acceptedWebSocketSubprotocol; /* websocket subprotocol, + * accepted during handshake */ +}; + + +/* This structure contains information about the HTTP request. */ +/* This structure may be extended in future versions. */ +struct mg_response_info { + int status_code; /* E.g. 200 */ + const char *status_text; /* E.g. "OK" */ + const char *http_version; /* E.g. "1.0", "1.1" */ + + long long content_length; /* Length (in bytes) of the request body, + can be -1 if no length was given. */ + + int num_headers; /* Number of HTTP headers */ + struct mg_header + http_headers[MG_MAX_HEADERS]; /* Allocate maximum headers */ +}; + + +/* Client certificate information (part of mg_request_info) */ +/* New nomenclature. */ +struct mg_client_cert { + const char *subject; + const char *issuer; + const char *serial; + const char *finger; +}; + +/* Old nomenclature. */ +struct client_cert { + const char *subject; + const char *issuer; + const char *serial; + const char *finger; }; @@ -158,13 +229,34 @@ struct mg_callbacks { #endif /* MG_LEGACY_INTERFACE */ /* Called when civetweb is closing a connection. The per-context mutex is - locked when this is invoked. This is primarily useful for noting when - a websocket is closing and removing it from any application-maintained - list of clients. + locked when this is invoked. + + Websockets: + Before mg_set_websocket_handler has been added, it was primarily useful + for noting when a websocket is closing, and used to remove it from any + application-maintained list of clients. Using this callback for websocket connections is deprecated: Use - mg_set_websocket_handler instead. */ + mg_set_websocket_handler instead. + + Connection specific data: + If memory has been allocated for the connection specific user data + (mg_request_info->conn_data, mg_get_user_connection_data), + this is the last chance to free it. + */ void (*connection_close)(const struct mg_connection *); +#if defined(MG_USE_OPEN_FILE) + /* Note: The "file in memory" feature is a deletion candidate, since + * it complicates the code, and does not add any value compared to + * "mg_add_request_handler". + * See this discussion thread: + * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI + * If you disagree, if there is any situation this is indeed useful + * and cannot trivially be replaced by another existing feature, + * please contribute to this discussion during the next 3 month + * (till end of April 2017), otherwise this feature might be dropped + * in future releases. */ + /* Called when civetweb tries to open a file. Used to intercept file open calls, and serve file data from memory instead. Parameters: @@ -174,10 +266,11 @@ struct mg_callbacks { Return value: NULL: do not serve file from memory, proceed with normal file open. non-NULL: pointer to the file contents in memory. data_len must be - initilized with the size of the memory block. */ + initialized with the size of the memory block. */ const char *(*open_file)(const struct mg_connection *, const char *path, size_t *data_len); +#endif /* Called when civetweb is about to serve Lua server page, if Lua support is enabled. @@ -223,6 +316,21 @@ struct mg_callbacks { Parameters: ctx: context handle */ void (*exit_context)(const struct mg_context *ctx); + + /* Called when initializing a new connection object. + * Can be used to initialize the connection specific user data + * (mg_request_info->conn_data, mg_get_user_connection_data). + * When the callback is called, it is not yet known if a + * valid HTTP(S) request will be made. + * Parameters: + * conn: not yet fully initialized connection object + * conn_data: output parameter, set to initialize the + * connection specific user data + * Return value: + * must be 0 + * Otherwise, the result is undefined + */ + int (*init_connection)(const struct mg_connection *conn, void **conn_data); }; @@ -294,11 +402,10 @@ typedef int (*mg_request_handler)(struct mg_connection *conn, void *cbdata); ctx: server context uri: the URI (exact or pattern) for the handler handler: the callback handler to use when the URI is requested. - If NULL, an already registered handler for this URI will be - removed. - The URI used to remove a handler must match exactly the one used - to - register it (not only a pattern match). + If NULL, an already registered handler for this URI will + be removed. + The URI used to remove a handler must match exactly the + one used to register it (not only a pattern match). cbdata: the callback data to give to the handler when it is called. */ CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx, const char *uri, @@ -342,6 +449,14 @@ typedef int (*mg_websocket_data_handler)(struct mg_connection *, typedef void (*mg_websocket_close_handler)(const struct mg_connection *, void *); +/* struct mg_websocket_subprotocols + * + * List of accepted subprotocols + */ +struct mg_websocket_subprotocols { + int nb_subprotocols; + char **subprotocols; +}; /* mg_set_websocket_handler @@ -356,10 +471,24 @@ mg_set_websocket_handler(struct mg_context *ctx, mg_websocket_close_handler close_handler, void *cbdata); +/* mg_set_websocket_handler + + Set or remove handler functions for websocket connections. + This function works similar to mg_set_request_handler - see there. */ +CIVETWEB_API void mg_set_websocket_handler_with_subprotocols( + struct mg_context *ctx, + const char *uri, + struct mg_websocket_subprotocols *subprotocols, + mg_websocket_connect_handler connect_handler, + mg_websocket_ready_handler ready_handler, + mg_websocket_data_handler data_handler, + mg_websocket_close_handler close_handler, + void *cbdata); + /* mg_authorization_handler - Some description here + Callback function definition for mg_set_auth_handler Parameters: conn: current connection information. @@ -411,6 +540,19 @@ CIVETWEB_API void * mg_get_user_connection_data(const struct mg_connection *conn); +/* Get a formatted link corresponding to the current request + + Parameters: + conn: current connection information. + buf: string buffer (out) + buflen: length of the string buffer + Returns: + <0: error + >=0: ok */ +CIVETWEB_API int +mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen); + + #if defined(MG_LEGACY_INTERFACE) /* Return array of strings that represent valid configuration options. For each option, option name and default value is returned, i.e. the @@ -427,7 +569,7 @@ struct mg_option { const char *default_value; }; - +/* Old nomenclature */ enum { CONFIG_TYPE_UNKNOWN = 0x0, CONFIG_TYPE_NUMBER = 0x1, @@ -435,9 +577,23 @@ enum { CONFIG_TYPE_FILE = 0x3, CONFIG_TYPE_DIRECTORY = 0x4, CONFIG_TYPE_BOOLEAN = 0x5, - CONFIG_TYPE_EXT_PATTERN = 0x6 + CONFIG_TYPE_EXT_PATTERN = 0x6, + CONFIG_TYPE_STRING_LIST = 0x7, + CONFIG_TYPE_STRING_MULTILINE = 0x8 }; +/* New nomenclature */ +enum { + MG_CONFIG_TYPE_UNKNOWN = 0x0, + MG_CONFIG_TYPE_NUMBER = 0x1, + MG_CONFIG_TYPE_STRING = 0x2, + MG_CONFIG_TYPE_FILE = 0x3, + MG_CONFIG_TYPE_DIRECTORY = 0x4, + MG_CONFIG_TYPE_BOOLEAN = 0x5, + MG_CONFIG_TYPE_EXT_PATTERN = 0x6, + MG_CONFIG_TYPE_STRING_LIST = 0x7, + MG_CONFIG_TYPE_STRING_MULTILINE = 0x8 +}; /* Return array of struct mg_option, representing all valid configuration options of civetweb.c. @@ -467,30 +623,45 @@ CIVETWEB_API int mg_get_server_ports(const struct mg_context *ctx, struct mg_server_ports *ports); +#if defined(MG_LEGACY_INTERFACE) /* Deprecated: Use mg_get_server_ports instead. */ CIVETWEB_API size_t mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl); +#endif /* Add, edit or delete the entry in the passwords file. - - This function allows an application to manipulate .htpasswd files on the - fly by adding, deleting and changing user records. This is one of the - several ways of implementing authentication on the server side. For another, - cookie-based way please refer to the examples/chat in the source tree. - - If password is not NULL, entry is added (or modified if already exists). - If password is NULL, entry is deleted. - - Return: - 1 on success, 0 on error. */ + * + * This function allows an application to manipulate .htpasswd files on the + * fly by adding, deleting and changing user records. This is one of the + * several ways of implementing authentication on the server side. For another, + * cookie-based way please refer to the examples/chat in the source tree. + * + * Parameter: + * passwords_file_name: Path and name of a file storing multiple passwords + * realm: HTTP authentication realm (authentication domain) name + * user: User name + * password: + * If password is not NULL, entry modified or added. + * If password is NULL, entry is deleted. + * + * Return: + * 1 on success, 0 on error. + */ CIVETWEB_API int mg_modify_passwords_file(const char *passwords_file_name, - const char *domain, + const char *realm, const char *user, const char *password); -/* Return information associated with the request. */ +/* Return information associated with the request. + * Use this function to implement a server and get data about a request + * from a HTTP/HTTPS client. + * Note: Before CivetWeb 1.10, this function could be used to read + * a response from a server, when implementing a client, although the + * values were never returned in appropriate mg_request_info elements. + * It is strongly advised to use mg_get_response_info for clients. + */ CIVETWEB_API const struct mg_request_info * mg_get_request_info(const struct mg_connection *); @@ -498,6 +669,13 @@ mg_get_request_info(const struct mg_connection *); CIVETWEB_API struct sockaddr * mg_get_local_addr(struct mg_connection *); +/* Return information associated with a HTTP/HTTPS response. + * Use this function in a client, to check the response from + * the server. */ +CIVETWEB_API const struct mg_response_info * +mg_get_response_info(const struct mg_connection *); + + /* Send data to the client. Return: 0 when the connection has been closed @@ -564,6 +742,7 @@ CIVETWEB_API void mg_unlock_context(struct mg_context *ctx); /* Opcodes, from http://tools.ietf.org/html/rfc6455 */ +/* Old nomenclature */ enum { WEBSOCKET_OPCODE_CONTINUATION = 0x0, WEBSOCKET_OPCODE_TEXT = 0x1, @@ -573,6 +752,15 @@ enum { WEBSOCKET_OPCODE_PONG = 0xa }; +/* New nomenclature */ +enum { + MG_WEBSOCKET_OPCODE_CONTINUATION = 0x0, + MG_WEBSOCKET_OPCODE_TEXT = 0x1, + MG_WEBSOCKET_OPCODE_BINARY = 0x2, + MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8, + MG_WEBSOCKET_OPCODE_PING = 0x9, + MG_WEBSOCKET_OPCODE_PONG = 0xa +}; /* Macros for enabling compiler-specific checks for printf-like arguments. */ #undef PRINTF_FORMAT_STRING @@ -601,24 +789,97 @@ CIVETWEB_API int mg_printf(struct mg_connection *, ...) PRINTF_ARGS(2, 3); +/* Send a part of the message body, if chunked transfer encoding is set. + * Only use this function after sending a complete HTTP request or response + * header with "Transfer-Encoding: chunked" set. */ +CIVETWEB_API int mg_send_chunk(struct mg_connection *conn, + const char *chunk, + unsigned int chunk_len); + + /* Send contents of the entire file together with HTTP headers. */ CIVETWEB_API void mg_send_file(struct mg_connection *conn, const char *path); + +/* Send HTTP error reply. */ +CIVETWEB_API void mg_send_http_error(struct mg_connection *conn, + int status_code, + PRINTF_FORMAT_STRING(const char *fmt), + ...) PRINTF_ARGS(3, 4); + + +/* Send HTTP digest access authentication request. + * Browsers will send a user name and password in their next request, showing + * an authentication dialog if the password is not stored. + * Parameters: + * conn: Current connection handle. + * realm: Authentication realm. If NULL is supplied, the sever domain + * set in the authentication_domain configuration is used. + * Return: + * < 0 Error + */ +CIVETWEB_API int +mg_send_digest_access_authentication_request(struct mg_connection *conn, + const char *realm); + + +/* Check if the current request has a valid authentication token set. + * A file is used to provide a list of valid user names, realms and + * password hashes. The file can be created and modified using the + * mg_modify_passwords_file API function. + * Parameters: + * conn: Current connection handle. + * realm: Authentication realm. If NULL is supplied, the sever domain + * set in the authentication_domain configuration is used. + * filename: Path and name of a file storing multiple password hashes. + * Return: + * > 0 Valid authentication + * 0 Invalid authentication + * < 0 Error (all values < 0 should be considered as invalid + * authentication, future error codes will have negative + * numbers) + * -1 Parameter error + * -2 File not found + */ +CIVETWEB_API int +mg_check_digest_access_authentication(struct mg_connection *conn, + const char *realm, + const char *filename); + + +/* Send contents of the entire file together with HTTP headers. + * Parameters: + * conn: Current connection handle. + * path: Full path to the file to send. + * mime_type: Content-Type for file. NULL will cause the type to be + * looked up by the file extension. + */ +CIVETWEB_API void mg_send_mime_file(struct mg_connection *conn, + const char *path, + const char *mime_type); + + /* Send contents of the entire file together with HTTP headers. Parameters: conn: Current connection information. path: Full path to the file to send. mime_type: Content-Type for file. NULL will cause the type to be looked up by the file extension. + additional_headers: Additional custom header fields appended to the header. + Each header should start with an X-, to ensure it is + not included twice. + NULL does not append anything. */ -CIVETWEB_API void mg_send_mime_file(struct mg_connection *conn, - const char *path, - const char *mime_type); +CIVETWEB_API void mg_send_mime_file2(struct mg_connection *conn, + const char *path, + const char *mime_type, + const char *additional_headers); + /* Store body data into a file. */ CIVETWEB_API long long mg_store_body(struct mg_connection *conn, const char *path); -/* Read entire request body and stor it in a file "path". +/* Read entire request body and store it in a file "path". Return: < 0 Error >= 0 Number of bytes stored in file "path". @@ -826,6 +1087,7 @@ struct mg_form_data_handler { /* Return values definition for the "field_found" callback in * mg_form_data_handler. */ +/* Old nomenclature */ enum { /* Skip this field (neither get nor store it). Continue with the * next field. */ @@ -838,6 +1100,18 @@ enum { FORM_FIELD_STORAGE_ABORT = 0x10 }; +/* New nomenclature */ +enum { + /* Skip this field (neither get nor store it). Continue with the + * next field. */ + MG_FORM_FIELD_STORAGE_SKIP = 0x0, + /* Get the field value. */ + MG_FORM_FIELD_STORAGE_GET = 0x1, + /* Store the field value into a file. */ + MG_FORM_FIELD_STORAGE_STORE = 0x2, + /* Stop parsing this request. Skip the remaining fields. */ + MG_FORM_FIELD_STORAGE_ABORT = 0x10 +}; /* Process form data. * Returns the number of fields handled, or < 0 in case of an error. @@ -862,8 +1136,8 @@ CIVETWEB_API const char *mg_get_builtin_mime_type(const char *file_name); /* Get text representation of HTTP status code. */ -CIVETWEB_API const char *mg_get_response_code_text(struct mg_connection *conn, - int response_code); +CIVETWEB_API const char * +mg_get_response_code_text(const struct mg_connection *conn, int response_code); /* Return CivetWeb version. */ @@ -900,7 +1174,7 @@ CIVETWEB_API char *mg_md5(char buf[33], ...); /* Print error message to the opened error log stream. This utilizes the provided logging configuration. - conn: connection + conn: connection (not used for sending data, but to get perameters) fmt: format string without the line return ...: variable argument list Example: @@ -910,15 +1184,12 @@ CIVETWEB_API void mg_cry(const struct mg_connection *conn, ...) PRINTF_ARGS(2, 3); -/* utility methods to compare two buffers, case incensitive. */ +/* utility methods to compare two buffers, case insensitive. */ CIVETWEB_API int mg_strcasecmp(const char *s1, const char *s2); - -/* set connection's http status */ -CIVETWEB_API void mg_set_http_status(struct mg_connection *conn, int status); - -/* utility method to compare two buffers, case incensitive. */ CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len); + /* set connection's http status */ +CIVETWEB_API void mg_set_http_status(struct mg_connection *conn, int status); /* Connect to a websocket as a client Parameters: @@ -986,7 +1257,7 @@ mg_connect_client_secure(const struct mg_client_options *client_options, enum { TIMEOUT_INFINITE = -1 }; - +enum { MG_TIMEOUT_INFINITE = -1 }; /* Wait for a response from the server Parameters: @@ -1005,9 +1276,16 @@ CIVETWEB_API int mg_get_response(struct mg_connection *conn, int timeout); -/* Check which features where set when civetweb has been compiled. +/* Check which features where set when the civetweb library has been compiled. + The function explicitly addresses compile time defines used when building + the library - it does not mean, the feature has been initialized using a + mg_init_library call. + mg_check_feature can be called anytime, even before mg_init_library has + been called. + Parameters: feature: specifies which feature should be checked + The value is a bit mask. The individual bits are defined as: 1 serve files (NO_FILES not set) 2 support HTTPS (NO_SSL not set) 4 support CGI (NO_CGI not set) @@ -1016,15 +1294,77 @@ CIVETWEB_API int mg_get_response(struct mg_connection *conn, 32 support Lua scripts and Lua server pages (USE_LUA is set) 64 support server side JavaScript (USE_DUKTAPE is set) 128 support caching (NO_CACHING not set) - The result is undefined for all other feature values. + 256 support server statistics (USE_SERVER_STATS is set) + The result is undefined, if bits are set that do not represent a + defined feature (currently: feature >= 512). + The result is undefined, if no bit is set (feature == 0). Return: - If feature is available > 0 - If feature is not available = 0 + If feature is available, the corresponding bit is set + If feature is not available, the bit is 0 */ CIVETWEB_API unsigned mg_check_feature(unsigned feature); +/* Get information on the system. Useful for support requests. + Parameters: + buffer: Store system information as string here. + buflen: Length of buffer (including a byte required for a terminating 0). + Return: + Available size of system information, exluding a terminating 0. + The information is complete, if the return value is smaller than buflen. + The result is a JSON formatted string, the exact content may vary. + Note: + It is possible to determine the required buflen, by first calling this + function with buffer = NULL and buflen = NULL. The required buflen is + one byte more than the returned value. +*/ +CIVETWEB_API int mg_get_system_info(char *buffer, int buflen); + + +/* Get context information. Useful for server diagnosis. + Parameters: + ctx: Context handle + buffer: Store context information here. + buflen: Length of buffer (including a byte required for a terminating 0). + Return: + Available size of system information, exluding a terminating 0. + The information is complete, if the return value is smaller than buflen. + The result is a JSON formatted string, the exact content may vary. + Note: + It is possible to determine the required buflen, by first calling this + function with buffer = NULL and buflen = NULL. The required buflen is + one byte more than the returned value. However, since the available + context information changes, you should allocate a few bytes more. +*/ +CIVETWEB_API int +mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen); + + +#ifdef MG_EXPERIMENTAL_INTERFACES +/* Get connection information. Useful for server diagnosis. + Parameters: + ctx: Context handle + idx: Connection index + buffer: Store context information here. + buflen: Length of buffer (including a byte required for a terminating 0). + Return: + Available size of system information, exluding a terminating 0. + The information is complete, if the return value is smaller than buflen. + The result is a JSON formatted string, the exact content may vary. + Note: + It is possible to determine the required buflen, by first calling this + function with buffer = NULL and buflen = NULL. The required buflen is + one byte more than the returned value. However, since the available + context information changes, you should allocate a few bytes more. +*/ +CIVETWEB_API int mg_get_connection_info(const struct mg_context *ctx, + int idx, + char *buffer, + int buflen); +#endif + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/ceph/src/civetweb/resources/Makefile.in-duktape b/ceph/src/civetweb/resources/Makefile.in-duktape index d7ad5cd1b..3a53f2e3d 100644 --- a/ceph/src/civetweb/resources/Makefile.in-duktape +++ b/ceph/src/civetweb/resources/Makefile.in-duktape @@ -1,5 +1,5 @@ # -# Copyright (c) 2015 the Civetweb developers +# Copyright (c) 2015-2017 the Civetweb developers # # License http://opensource.org/licenses/mit-license.php MIT License # @@ -8,16 +8,32 @@ ifndef WITH_DUKTAPE $(error WITH_DUKTAPE is not defined) endif -# Duktape default version is 1.3.0 (103) -WITH_DUKTAPE_VERSION ?= 103 +# Duktape default version is 1.5.2 (105) +WITH_DUKTAPE_VERSION ?= 105 DUKTAPE_VERSION_KNOWN = 0 # Select src and header according to the Duktape version -ifeq ($(WITH_DUKTAPE_VERSION), 103) - $(info Duktape: Using version 1.3.0) - DUKTAPE_DIR = src/third_party/duktape-1.3.0/src - DUKTAPE_SHARED_LIB_FLAG = -lduktape1.3 - DUKTAPE_CFLAGS = -DDUKTAPE_VERSION_MAKEFILE=501 +ifeq ($(WITH_DUKTAPE_VERSION), 105) + $(info Duktape: Using version 1.5.2) + DUKTAPE_DIR = src/third_party/duktape-1.5.2/src + DUKTAPE_SHARED_LIB_FLAG = -lduktape1.5 + DUKTAPE_CFLAGS = -DDUKTAPE_VERSION_MAKEFILE=105 + DUKTAPE_VERSION_KNOWN = 1 +endif + +ifeq ($(WITH_DUKTAPE_VERSION), 108) + $(info Duktape: Using version 1.8.0) + DUKTAPE_DIR = src/third_party/duktape-1.8.0/src + DUKTAPE_SHARED_LIB_FLAG = -lduktape1.8 + DUKTAPE_CFLAGS = -DDUKTAPE_VERSION_MAKEFILE=108 + DUKTAPE_VERSION_KNOWN = 1 +endif + +ifeq ($(WITH_DUKTAPE_VERSION), 201) + $(info Duktape: Using version 2.1.1) + DUKTAPE_DIR = src/third_party/duktape-2.1.1/src + DUKTAPE_SHARED_LIB_FLAG = -lduktape2.1 + DUKTAPE_CFLAGS = -DDUKTAPE_VERSION_MAKEFILE=201 DUKTAPE_VERSION_KNOWN = 1 endif @@ -44,7 +60,7 @@ else DUKTAPE_SOURCE_FILES = duktape.c ifeq ($(WITH_DUKTAPE_VERSION), 104) -# DUKTAPE_SOURCE_FILES += +# DUKTAPE_SOURCE_FILES += ... TODO ... endif $(info Duktape: using static library) @@ -57,4 +73,5 @@ DUKTAPE_OBJECTS = $(DUKTAPE_SOURCES:.c=.o) OBJECTS += $(DUKTAPE_OBJECTS) CFLAGS += $(DUKTAPE_CFLAGS) SOURCE_DIRS = $(DUKTAPE_DIR) +BUILD_DIRS += $(BUILD_DIR)/$(DUKTAPE_DIR) diff --git a/ceph/src/civetweb/resources/Makefile.in-lua b/ceph/src/civetweb/resources/Makefile.in-lua index 52474781e..e91d019c9 100644 --- a/ceph/src/civetweb/resources/Makefile.in-lua +++ b/ceph/src/civetweb/resources/Makefile.in-lua @@ -1,6 +1,6 @@ # # Copyright (c) 2013 No Face Press, LLC -# Copyright (c) 2014-2015 the Civetweb developers +# Copyright (c) 2014-2017 the Civetweb developers # # License http://opensource.org/licenses/mit-license.php MIT License # @@ -29,8 +29,8 @@ ifeq ($(WITH_LUA_VERSION), 502) LUA_VERSION_KNOWN = 1 endif ifeq ($(WITH_LUA_VERSION), 503) - $(info Lua: Using version 5.3.1) - LUA_DIR = src/third_party/lua-5.3.1/src + $(info Lua: Using version 5.3.3) + LUA_DIR = src/third_party/lua-5.3.3/src LUA_SHARED_LIB_FLAG = -llua5.3 LUA_CFLAGS = -DLUA_COMPAT_5_2 -DLUA_VERSION_MAKEFILE=503 LUA_VERSION_KNOWN = 1 @@ -108,6 +108,7 @@ LUA_OBJECTS = $(LUA_SOURCES:.c=.o) OBJECTS += $(LUA_OBJECTS) CFLAGS += $(LUA_CFLAGS) SOURCE_DIRS = $(LUA_DIR) +BUILD_DIRS += $(BUILD_DIR)/$(LUA_DIR) ifneq ($(WITH_LUA_VERSION), 501) diff --git a/ceph/src/civetweb/resources/Makefile.in-os b/ceph/src/civetweb/resources/Makefile.in-os index 9ad113276..a75913486 100644 --- a/ceph/src/civetweb/resources/Makefile.in-os +++ b/ceph/src/civetweb/resources/Makefile.in-os @@ -20,3 +20,4 @@ ifeq ($(TARGET_OS),) endif endif endif + diff --git a/ceph/src/civetweb/resources/cert/client.crt b/ceph/src/civetweb/resources/cert/client.crt index d6cd7ef8e..f6bbdd868 100644 --- a/ceph/src/civetweb/resources/cert/client.crt +++ b/ceph/src/civetweb/resources/cert/client.crt @@ -1,14 +1,19 @@ -----BEGIN CERTIFICATE----- -MIICOTCCAaICCQCXNPrLNIw8IDANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJ4 -eDELMAkGA1UECAwCeHgxCzAJBgNVBAcMAnh4MQswCQYDVQQKDAJ4eDELMAkGA1UE -CwwCeHgxCzAJBgNVBAMMAnh4MREwDwYJKoZIhvcNAQkBFgJ4eDAeFw0xNTEwMjUy -MzMxNDJaFw0yNTEwMjIyMzMxNDJaMGExCzAJBgNVBAYTAnh4MQswCQYDVQQIDAJ4 -eDELMAkGA1UEBwwCeHgxCzAJBgNVBAoMAnh4MQswCQYDVQQLDAJ4eDELMAkGA1UE -AwwCeHgxETAPBgkqhkiG9w0BCQEWAnh4MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQDGwWIIU2KUEufa0Ga5lnm7I8cX4LPRIFX4zL3g1Kuw27eRaJWJLz3Y97oi -m0fUmhhKJoEFDxj9U4UbXZWMxzH5F8RfupUu+9yDqTWjTRaUQiM/C7dSPEevfqNP -zBoERPrMzm9W5d8Ke04vpUzk0duoE6vyNQVECroNlHY7R4zQjwIDAQABMA0GCSqG -SIb3DQEBCwUAA4GBAKZiZ2+sYJWFnQcfqcDJBwrbTo98SSxfryPmeVQSuM8AXC4I -baX+fqkatdFidDBl96Aq8pDfqeAz+gqRoJ+Dx7opn5/b0WcB0lD+v25x+nO8g4z7 -HBzpVtvRTkC7dGase72csnqvyWm1xTSiHNRIghl0kZy8wb6V9GmJsHxBoKWN +MIIDBjCCAe4CCQCFpskbTEyGpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE3MDkwMzE5MjIwNVoXDTI3MDkwMTE5MjIwNVowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANyFUuYxv/uexSr/K9aSmcnEcylNH4S3NdlvMwFvW3XFqAV05tV6HnPnSELEk6t3 +8aMDUGKDBrrjwsVK6+S7OyrkioXeB9dWldHbqD7o3MkIM3sUxUtaR6x0RMZ+sIX4 +XpE0xULcip1bG0etP4Z2frEP2IOOValQcm4SCnKYZJyTr/oR31NmlIPU/47s74U6 +rqwwUE92bzvf1jGeUHEn7IAgSJNIUBNsOIdRQAMBuTJIAmG2qawXaetjLi/NBwNS +d0OX2v3o9SrA+ZhQYpPG5xp3B3ncHgVvmhmp7hUdlYbiemcUHn18hZjxPVZLbtY8 +gQldrWyMZkVabSZjuIH3IKcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAUZsxxYVK +l0tH8E0FCnRJTvG6gjOeiqJRIk7Mmg+hfFZK/ewqBixxg1OBM/xmPXfnI/ULRz74 +UMXnyDIsGakzrFDqWqPt3xots35yHHo2ZkVao6gV4qx0Reu86qeN5iRvG0EjoGMD +7XRaw56E0XhvMBJW1CiUg944HSw4ptJli0dJCYa+P9s1Fop3lA0d9+dwKMKUyCDr +yBz4XjyO9jXSQC/t0fkxC4gHhdH/ZaAq0Lem6Xxc40ZwoVc1+dHWFxn8d6L/RYvb +16gOuw6s2Xt9h2K8OFKzehOgNZAkI2oUELRFUx9Wc8/Bcl6uEkBmPHRqeX5l35jo +ztBrpAEsCy0cGg== -----END CERTIFICATE----- diff --git a/ceph/src/civetweb/resources/cert/client.csr b/ceph/src/civetweb/resources/cert/client.csr index 8c5dbdce6..beb846694 100644 --- a/ceph/src/civetweb/resources/cert/client.csr +++ b/ceph/src/civetweb/resources/cert/client.csr @@ -1,11 +1,16 @@ -----BEGIN CERTIFICATE REQUEST----- -MIIBoTCCAQoCAQAwYTELMAkGA1UEBhMCeHgxCzAJBgNVBAgMAnh4MQswCQYDVQQH -DAJ4eDELMAkGA1UECgwCeHgxCzAJBgNVBAsMAnh4MQswCQYDVQQDDAJ4eDERMA8G -CSqGSIb3DQEJARYCeHgwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMbBYghT -YpQS59rQZrmWebsjxxfgs9EgVfjMveDUq7Dbt5FolYkvPdj3uiKbR9SaGEomgQUP -GP1ThRtdlYzHMfkXxF+6lS773IOpNaNNFpRCIz8Lt1I8R69+o0/MGgRE+szOb1bl -3wp7Ti+lTOTR26gTq/I1BUQKug2UdjtHjNCPAgMBAAGgADANBgkqhkiG9w0BAQsF -AAOBgQCVJKEisDii5qFbV75rOGF+tTChv3c051pWerl8U42s/MQ3jhzNb8+i7f2n -Kn4yZU3u91xtAruAoKFPSnFpgQKyBRv57g5eM03nrUUImZcRT5Kkf4YsqRMsZ2yH -MYk6QbTrJwibUoqEUUFgv0n5ONUBoEvhzZr0K9KZ3DLyIg1rpQ== +MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANyFUuYxv/uexSr/K9aSmcnEcylNH4S3NdlvMwFv +W3XFqAV05tV6HnPnSELEk6t38aMDUGKDBrrjwsVK6+S7OyrkioXeB9dWldHbqD7o +3MkIM3sUxUtaR6x0RMZ+sIX4XpE0xULcip1bG0etP4Z2frEP2IOOValQcm4SCnKY +ZJyTr/oR31NmlIPU/47s74U6rqwwUE92bzvf1jGeUHEn7IAgSJNIUBNsOIdRQAMB +uTJIAmG2qawXaetjLi/NBwNSd0OX2v3o9SrA+ZhQYpPG5xp3B3ncHgVvmhmp7hUd +lYbiemcUHn18hZjxPVZLbtY8gQldrWyMZkVabSZjuIH3IKcCAwEAAaAAMA0GCSqG +SIb3DQEBCwUAA4IBAQB/bapQm4nxXA01msL6nkjiVaeh/mj8Cr8sPFtQXVu+hxl9 +mjbisxDXwPhiFOiTlokQkINf+RMxQsVNr2y/sGZrSMimabwODDXnPpyir4b2WOWp +VQQWbgnMVnvgKsjBpLLDr8VnLBiQ3mED+2QV0bxxJSgvvEuiZx/BlCgiu77D/8kj +XUY/CXIBi00fIYigpRRdv2WtMQjtQe2fCSZZKOWu2ZWu2o24kEk28x5LO/WaJ4Ft +lUHFOIp/wkKz/US4mbdQaD0bsg7MirAyGrCmZIHqQDhdDWq+o/brI7N/8yOk3qwc +qPGkr9PYIPnuzZwStLJlPxKGXjCA40HpdmWA0kyc -----END CERTIFICATE REQUEST----- diff --git a/ceph/src/civetweb/resources/cert/client.key b/ceph/src/civetweb/resources/cert/client.key index ea9e739b7..f041acc0c 100644 --- a/ceph/src/civetweb/resources/cert/client.key +++ b/ceph/src/civetweb/resources/cert/client.key @@ -1,15 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDGwWIIU2KUEufa0Ga5lnm7I8cX4LPRIFX4zL3g1Kuw27eRaJWJ -Lz3Y97oim0fUmhhKJoEFDxj9U4UbXZWMxzH5F8RfupUu+9yDqTWjTRaUQiM/C7dS -PEevfqNPzBoERPrMzm9W5d8Ke04vpUzk0duoE6vyNQVECroNlHY7R4zQjwIDAQAB -AoGAUPrNxHKlAYvKZ77te8QxiOwE3FezLAuuu5Y/7vD3mzGKU3Z3JtPWsSYN8ret -xpOaPev+OV9zYRO8ce/pVNh8JTcvywU9SaaxzrMVIq+8rOfM8oCXwpKr7FqV6fO3 -a9JzofV6A2x3mzWqyixRVSGBWTC3Oc5+uaTX5pmJvMFgKLECQQDxFopXbhgPUVtQ -Wa5onj3qDtYsuJALBDaHDV7nSoQySZpHn1DS/w1n+INOuwkXXfMzqdRDKGDh5VVe -5rF1k1nVAkEA0wyI7aXYIJuYli5fCN6bwGQTwmwoWbyDDE+VkZlMUm8KhIzdnFjP -j9+ntNshNYyKf6H9XqxuizNyiLyiWl+u0wJAXLWgSXLKycktZj62dQC1Kna+IcBv -k+zw0wpvPl5Ha9cl/vji6eCu1RaZ2ALQwi2cwndCavjyGKxKIg5wm5goaQJAc4dC -EW0ecUMbdOJvbWiGM/vUgTI5qF20EvIhuvECwYE9ba+6xBItlOFmaW8mr6x+SD3B -d6jGXnbMNKOl7/i+twJBANIFBVZBal85Wn0V5MJFDWLB1vPSxXwb4OBwVD+j52H7 -YwpRbUn3/4CkiagDPdzio80WkWdkqpGZoVyDUpZi5Fg= +MIIEpAIBAAKCAQEA3IVS5jG/+57FKv8r1pKZycRzKU0fhLc12W8zAW9bdcWoBXTm +1Xoec+dIQsSTq3fxowNQYoMGuuPCxUrr5Ls7KuSKhd4H11aV0duoPujcyQgzexTF +S1pHrHRExn6whfhekTTFQtyKnVsbR60/hnZ+sQ/Yg45VqVBybhIKcphknJOv+hHf +U2aUg9T/juzvhTqurDBQT3ZvO9/WMZ5QcSfsgCBIk0hQE2w4h1FAAwG5MkgCYbap +rBdp62MuL80HA1J3Q5fa/ej1KsD5mFBik8bnGncHedweBW+aGanuFR2VhuJ6ZxQe +fXyFmPE9Vktu1jyBCV2tbIxmRVptJmO4gfcgpwIDAQABAoIBAEpiBlZzTYi4Q1V/ +gO/9vzYZt6akxw7jJZzUL2Y6g6U0KLq+deZoLMF3sB4lZJIgATe1NHYmMCz2Coq1 +/N/Ib+rF8Bu7ivWN1TdWWmft8Bs3UvYfSXVjXG3FQjWaIjzuTCe6nxcwgOkXBBqn +S5g1fAKJj8TATBCyfAa4uyFwWe+eGRs0W9pOMP8eU0EtvTer34rSU4L/LG3d7UcI +upm/0T5QeLqv6Htv8UbHNQto701vJQVdWLavALMXGfGO112yTSz7OpitKpBEYDrV +3+781zYm8AKkFIsRMXVK2HiBEF43zIrnNuoozsKpps/tZdlv9VqCSJ4hIaHm9mxJ +3zMN3OECgYEA8dr5w68jTLrthDZ2qOG/6tZw9fMfXoF7hSUXplgxMN5Sohfr23Xm +/IHVm7oiqhDNNZzplGyux7jB00x2/1ltOzay5mx4PMMLlsDBgiURgUwqS8C8dPVh +0sN2RytdKGDmFP6lnKS7c15CEw1ChvdL4RwtqzjTKE0ZOK3zUY5/MykCgYEA6Wru +Dusip4p4PA1K6eiCoC6SaqCuQCB7ZR5WPR5szAFkgoW63rNtC8S4Bl1qXXUb/v/V +ptaVsGrqBc8/CxvCac1KCREbcyjuVWUAfw2VwdwgDbfrEieWrZNvsDs86EgB+Bo4 +Jm/cUjrFqSTJAbtvp4SYl1reax86XmCsHhNNf08CgYEApAhxd9/0IBlz+ET8K8SY +5sy0ZouTjgRh40bqCF8uVcej4d45kGoh1Ma2Ot1+nzuwApm+7nTcAgd0JjxpRPzB +EfUiVxfgYM2ksYVgeUVs3vXqheBdsTGwPENnmBN4Jme6BSlE573uiOu4ArXulh1p +sG7tJoDu7hmEbqXELl9oNCkCgYEA51zWGnN3JhpakyuZ1cBhueRvvMEH9wg7Rz+K +u4oszQmUVsu3Locqzz9uKODvTTOHTHrJi1WnifZvgNKr6pbZXYXenJ4YV01676nt +lAIjLsTCANcMajJTaDl7u3L8LEEzsnhKr86w09Dtm3qawtzHD4Seu2eWjxelA2dP +M4BukIECgYAn5n+HhCi5JD3I1VCX70uE5nj8alYyQ85qE57Lopmau1RyVfP4oeCt +gMsy0o7vIF+xW1Z2yDxm+mJghOY/myDsbTGX9G8rY7PC7tWE8okjsQT5UoayFzKp +mmvrTV8TQBVcTQqn0Jyj7T5MBnuwfioXYN9pKPQlvc4pPmHbqPi7CA== -----END RSA PRIVATE KEY----- diff --git a/ceph/src/civetweb/resources/cert/client.key.orig b/ceph/src/civetweb/resources/cert/client.key.orig index 31489cdc3..6b30836ae 100644 --- a/ceph/src/civetweb/resources/cert/client.key.orig +++ b/ceph/src/civetweb/resources/cert/client.key.orig @@ -1,18 +1,30 @@ -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,74B669EA97409DB5 +DEK-Info: DES-EDE3-CBC,161D2DE9FC3C5EE4 -U8mySuY/I28r8dygZbyHF9K5VFPekhar4zgN2p6wUyrIT9UvA0Y75VE6Pu55+FZS -JEiR+5btbONt2Lf7z52zi8bv8cb+IJryjSoGkk9Klesmwc9qkUxtuZosdIoZKGFl -SgSNecK7QYOu66PK4GOi47CFsKuKT4pR8A8Kt11PYTpXDNGomcsdS3DNEbpxvj7F -/D/1V24IMu+cknL3r6wwL0stB3idwS+4Oq/JLosKHC5mB6+Pu285K6/NWUo5FqLy -WgzCWzFzzQy3vBce30HOf2gCUJ++2JKoBa8wdj06ei0OTz6oFWAvftv1fTen6cyW -LG5uAmNPpv4PmtTpOtNJtd8VFpShxiCbYm772MXiDRNiLL9iMsS9OtgTkxHyqRqr -i8RRKzZCFzf4+xTGxO6GkkFV0/W/PM+TnvFWoWOviCjJJOFGwrQAUzRFce3UAU8V -sSmvnE0mGvREQAUiw15onGaHKT/ivzFFutgghrcrjpGH55j/zp5gxD+WDeDqAgNA -RPk0l63D9CrjyTuyTX1H35V1+EZ9YYP5tZ3wGn6i3WCC3WjHqDg5EZHRprjvPw7p -rfurs33qHUon42aM1G/dJ+jtn4993RdCvCztxW6aBp+nLEEROMA/0HCZJeM9lE7L -nWAy+jkn/6wRoATa01fEPHozju0HQhCrPcxjrJ8tIVgI1iEL2xw7STlvo6BZcnP2 -oGLMiEk5gmHCOonh+taLkFhKP+F0cSZJlJcmEr6YYzhh7FoR+sKEb2Cx2n2ySuhv -LYh1Wn4T0Xmau7OFX2Pc+d5zBaW6lYn/ZUw8GbaDqNd3sT/UICC0Ww== +U+3WYIvh4n4cJouZXJkuPMUucnymOWME9ZPBs3CzbWao/HSYS7tEh0gUMb6VtkQo +zq/jQUO2aecWC3+LPZlkUGGWwCU3OCgyFW9xiMRduzKhbPUig+4k9aeKki5RypmR +XFnn/W5ddJSHTVgQI0hF7ZxvC86ldBkCHzSwkKyL8dwBNouXyMgl4PfaZ90N3/pZ +jBnuqbwF1EN0V6OYo3QSxsifpu2M62a229yW9U0/vV7bkGgyqTbtV6V6ny5+IWn+ +r99bb+hS1SSt5VVuHfNKh06ww0Mc7bSfeyVcdgoT5ltftsRWEA1Au5DfS+nhztVf +0l/yiMTm60x61WuXsbQz+4hwH7nCAMIFbBmCYbP/eqY9BIiKy9Ue7vOouTHdi7Op +wQL/r3Wc/+IcssoExITnOBX2San6NvtC7ej+8Wf/wKOh5mTp4uT5cbdif3ifj7uo +GmYbWNJSo0VVtl1nru9uSIbJSKVzMcDO2aVbofCGB4KUpkm+3Sw2ZnbJ6o/AVZb3 +ip7NoudU11d6KBzpyvfyFzSNfGVmtasB24BYt22vSQWJ5Ob5MQgg+zFEpGUeoq6p +LqRaZCDqXHsofM49JEbU/32SV3JhSjfzJ9gVG+lymGZIdmYD4y+SH/6K0QtCN9cY +7++96vAPYgKmJ6vK1N8o6owDkxQ3+FilKWanp2rwETc1RyWSg5hi62+8YllmsQXc +3zvFXgCS+yfAKXqtHTugtb6c8o2RuPdpNtVmtncEnf3OeuP/gDbqLumzHRDQk+o1 +rgGiLsvY4MmbmS0D/c4NZ8fyBqN7d2TRHnHS6mpqgzpKHOuRPmLQ+azmf3ISY9m4 +H8ROjKqTMHUfxQRKizHPTRjtvYjk/uXBrpnDa2buPaW+m1brsiHdhruhB6QPaJGQ +8uFFHyur5ZRMQhST/fWLmNxPX9CAsXBuKm1cPJWw+QzR8uo7bFwups1ODrLj0L0U +ECAq343KS6aoCMoLGw4EZRHeSdrequtsaGFHMtweSxs7PJR+UVLf/JSw4f0L4Pa8 +GvY9nBGrI/uoN4H88YR1NjxLCzU5mZ3yLV4ZL9zGq1gX5ZfAr1b9i2pJI4daBFvW +gJBSzoiN9dq4I4ZZgZ7KSTG2n2mnPPlOhAIgabwpDb2buf0GrZYhgby78Vwy3bdb +Yk8ToEvLnKzDH8P4JjClIVC7R+bfH1uUO+uDRYZBlpkzc0+HgagW0vt9xZpWrdOm +DJeZ7/ciCbD+90b1mc8xkPgegKjvrMfEMk81GEGhv28FpIbEAX9nuA4UaQHI58s/ +tgQ3kThVrlJCC/77teNMubcIWycV8ufm4NgDeGtmIP47Z9Vdrv+VFv0hib3hch9M +7lIJX0aSVRHhEFi6QquQmTlvEB/Z8T640k9ZGiTgkGEFrEh6nnGeiLP+WJodLd/u +CKkx3KLEi8T90dsPhyo852o+oKOFMA/nEGEOBE7VcgOGkZ2NTBOerVZrBp6T0PGi +0x2A32YDMjeI19CdsvxgIq7wj9wXuWDXAFV2Ond75XwM4CnGSKefh+Z82ZlfnmNf +GyKsUSn0Nno58y5LLzXw06E4Wp4WtQcw4KiiaEYA6s92RAsoslY6XqdYSeSvtSz2 -----END RSA PRIVATE KEY----- diff --git a/ceph/src/civetweb/resources/cert/client.pem b/ceph/src/civetweb/resources/cert/client.pem index 331fd708e..6974c4c81 100644 --- a/ceph/src/civetweb/resources/cert/client.pem +++ b/ceph/src/civetweb/resources/cert/client.pem @@ -1,29 +1,46 @@ -----BEGIN CERTIFICATE----- -MIICOTCCAaICCQCXNPrLNIw8IDANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJ4 -eDELMAkGA1UECAwCeHgxCzAJBgNVBAcMAnh4MQswCQYDVQQKDAJ4eDELMAkGA1UE -CwwCeHgxCzAJBgNVBAMMAnh4MREwDwYJKoZIhvcNAQkBFgJ4eDAeFw0xNTEwMjUy -MzMxNDJaFw0yNTEwMjIyMzMxNDJaMGExCzAJBgNVBAYTAnh4MQswCQYDVQQIDAJ4 -eDELMAkGA1UEBwwCeHgxCzAJBgNVBAoMAnh4MQswCQYDVQQLDAJ4eDELMAkGA1UE -AwwCeHgxETAPBgkqhkiG9w0BCQEWAnh4MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQDGwWIIU2KUEufa0Ga5lnm7I8cX4LPRIFX4zL3g1Kuw27eRaJWJLz3Y97oi -m0fUmhhKJoEFDxj9U4UbXZWMxzH5F8RfupUu+9yDqTWjTRaUQiM/C7dSPEevfqNP -zBoERPrMzm9W5d8Ke04vpUzk0duoE6vyNQVECroNlHY7R4zQjwIDAQABMA0GCSqG -SIb3DQEBCwUAA4GBAKZiZ2+sYJWFnQcfqcDJBwrbTo98SSxfryPmeVQSuM8AXC4I -baX+fqkatdFidDBl96Aq8pDfqeAz+gqRoJ+Dx7opn5/b0WcB0lD+v25x+nO8g4z7 -HBzpVtvRTkC7dGase72csnqvyWm1xTSiHNRIghl0kZy8wb6V9GmJsHxBoKWN +MIIDBjCCAe4CCQCFpskbTEyGpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE3MDkwMzE5MjIwNVoXDTI3MDkwMTE5MjIwNVowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANyFUuYxv/uexSr/K9aSmcnEcylNH4S3NdlvMwFvW3XFqAV05tV6HnPnSELEk6t3 +8aMDUGKDBrrjwsVK6+S7OyrkioXeB9dWldHbqD7o3MkIM3sUxUtaR6x0RMZ+sIX4 +XpE0xULcip1bG0etP4Z2frEP2IOOValQcm4SCnKYZJyTr/oR31NmlIPU/47s74U6 +rqwwUE92bzvf1jGeUHEn7IAgSJNIUBNsOIdRQAMBuTJIAmG2qawXaetjLi/NBwNS +d0OX2v3o9SrA+ZhQYpPG5xp3B3ncHgVvmhmp7hUdlYbiemcUHn18hZjxPVZLbtY8 +gQldrWyMZkVabSZjuIH3IKcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAUZsxxYVK +l0tH8E0FCnRJTvG6gjOeiqJRIk7Mmg+hfFZK/ewqBixxg1OBM/xmPXfnI/ULRz74 +UMXnyDIsGakzrFDqWqPt3xots35yHHo2ZkVao6gV4qx0Reu86qeN5iRvG0EjoGMD +7XRaw56E0XhvMBJW1CiUg944HSw4ptJli0dJCYa+P9s1Fop3lA0d9+dwKMKUyCDr +yBz4XjyO9jXSQC/t0fkxC4gHhdH/ZaAq0Lem6Xxc40ZwoVc1+dHWFxn8d6L/RYvb +16gOuw6s2Xt9h2K8OFKzehOgNZAkI2oUELRFUx9Wc8/Bcl6uEkBmPHRqeX5l35jo +ztBrpAEsCy0cGg== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDGwWIIU2KUEufa0Ga5lnm7I8cX4LPRIFX4zL3g1Kuw27eRaJWJ -Lz3Y97oim0fUmhhKJoEFDxj9U4UbXZWMxzH5F8RfupUu+9yDqTWjTRaUQiM/C7dS -PEevfqNPzBoERPrMzm9W5d8Ke04vpUzk0duoE6vyNQVECroNlHY7R4zQjwIDAQAB -AoGAUPrNxHKlAYvKZ77te8QxiOwE3FezLAuuu5Y/7vD3mzGKU3Z3JtPWsSYN8ret -xpOaPev+OV9zYRO8ce/pVNh8JTcvywU9SaaxzrMVIq+8rOfM8oCXwpKr7FqV6fO3 -a9JzofV6A2x3mzWqyixRVSGBWTC3Oc5+uaTX5pmJvMFgKLECQQDxFopXbhgPUVtQ -Wa5onj3qDtYsuJALBDaHDV7nSoQySZpHn1DS/w1n+INOuwkXXfMzqdRDKGDh5VVe -5rF1k1nVAkEA0wyI7aXYIJuYli5fCN6bwGQTwmwoWbyDDE+VkZlMUm8KhIzdnFjP -j9+ntNshNYyKf6H9XqxuizNyiLyiWl+u0wJAXLWgSXLKycktZj62dQC1Kna+IcBv -k+zw0wpvPl5Ha9cl/vji6eCu1RaZ2ALQwi2cwndCavjyGKxKIg5wm5goaQJAc4dC -EW0ecUMbdOJvbWiGM/vUgTI5qF20EvIhuvECwYE9ba+6xBItlOFmaW8mr6x+SD3B -d6jGXnbMNKOl7/i+twJBANIFBVZBal85Wn0V5MJFDWLB1vPSxXwb4OBwVD+j52H7 -YwpRbUn3/4CkiagDPdzio80WkWdkqpGZoVyDUpZi5Fg= +MIIEpAIBAAKCAQEA3IVS5jG/+57FKv8r1pKZycRzKU0fhLc12W8zAW9bdcWoBXTm +1Xoec+dIQsSTq3fxowNQYoMGuuPCxUrr5Ls7KuSKhd4H11aV0duoPujcyQgzexTF +S1pHrHRExn6whfhekTTFQtyKnVsbR60/hnZ+sQ/Yg45VqVBybhIKcphknJOv+hHf +U2aUg9T/juzvhTqurDBQT3ZvO9/WMZ5QcSfsgCBIk0hQE2w4h1FAAwG5MkgCYbap +rBdp62MuL80HA1J3Q5fa/ej1KsD5mFBik8bnGncHedweBW+aGanuFR2VhuJ6ZxQe +fXyFmPE9Vktu1jyBCV2tbIxmRVptJmO4gfcgpwIDAQABAoIBAEpiBlZzTYi4Q1V/ +gO/9vzYZt6akxw7jJZzUL2Y6g6U0KLq+deZoLMF3sB4lZJIgATe1NHYmMCz2Coq1 +/N/Ib+rF8Bu7ivWN1TdWWmft8Bs3UvYfSXVjXG3FQjWaIjzuTCe6nxcwgOkXBBqn +S5g1fAKJj8TATBCyfAa4uyFwWe+eGRs0W9pOMP8eU0EtvTer34rSU4L/LG3d7UcI +upm/0T5QeLqv6Htv8UbHNQto701vJQVdWLavALMXGfGO112yTSz7OpitKpBEYDrV +3+781zYm8AKkFIsRMXVK2HiBEF43zIrnNuoozsKpps/tZdlv9VqCSJ4hIaHm9mxJ +3zMN3OECgYEA8dr5w68jTLrthDZ2qOG/6tZw9fMfXoF7hSUXplgxMN5Sohfr23Xm +/IHVm7oiqhDNNZzplGyux7jB00x2/1ltOzay5mx4PMMLlsDBgiURgUwqS8C8dPVh +0sN2RytdKGDmFP6lnKS7c15CEw1ChvdL4RwtqzjTKE0ZOK3zUY5/MykCgYEA6Wru +Dusip4p4PA1K6eiCoC6SaqCuQCB7ZR5WPR5szAFkgoW63rNtC8S4Bl1qXXUb/v/V +ptaVsGrqBc8/CxvCac1KCREbcyjuVWUAfw2VwdwgDbfrEieWrZNvsDs86EgB+Bo4 +Jm/cUjrFqSTJAbtvp4SYl1reax86XmCsHhNNf08CgYEApAhxd9/0IBlz+ET8K8SY +5sy0ZouTjgRh40bqCF8uVcej4d45kGoh1Ma2Ot1+nzuwApm+7nTcAgd0JjxpRPzB +EfUiVxfgYM2ksYVgeUVs3vXqheBdsTGwPENnmBN4Jme6BSlE573uiOu4ArXulh1p +sG7tJoDu7hmEbqXELl9oNCkCgYEA51zWGnN3JhpakyuZ1cBhueRvvMEH9wg7Rz+K +u4oszQmUVsu3Locqzz9uKODvTTOHTHrJi1WnifZvgNKr6pbZXYXenJ4YV01676nt +lAIjLsTCANcMajJTaDl7u3L8LEEzsnhKr86w09Dtm3qawtzHD4Seu2eWjxelA2dP +M4BukIECgYAn5n+HhCi5JD3I1VCX70uE5nj8alYyQ85qE57Lopmau1RyVfP4oeCt +gMsy0o7vIF+xW1Z2yDxm+mJghOY/myDsbTGX9G8rY7PC7tWE8okjsQT5UoayFzKp +mmvrTV8TQBVcTQqn0Jyj7T5MBnuwfioXYN9pKPQlvc4pPmHbqPi7CA== -----END RSA PRIVATE KEY----- diff --git a/ceph/src/civetweb/resources/cert/client.pfx b/ceph/src/civetweb/resources/cert/client.pfx index 5797f2355..601b3d51a 100644 Binary files a/ceph/src/civetweb/resources/cert/client.pfx and b/ceph/src/civetweb/resources/cert/client.pfx differ diff --git a/ceph/src/civetweb/resources/cert/make_certs b/ceph/src/civetweb/resources/cert/make_certs deleted file mode 100644 index 1dcf32b02..000000000 --- a/ceph/src/civetweb/resources/cert/make_certs +++ /dev/null @@ -1,31 +0,0 @@ -#using "pass" for every password - -openssl genrsa -des3 -out client.key 1024 -openssl req -new -key client.key -out client.csr - -cp client.key client.key.orig - -openssl rsa -in client.key.orig -out client.key - -openssl x509 -req -days 3650 -in client.csr -signkey client.key -out client.crt - -cp client.crt client.pem -cat client.key >> client.pem - -openssl pkcs12 -export -inkey client.key -in client.pem -name ClientName -out client.pfx - - - -openssl genrsa -des3 -out server.key 1024 -openssl req -new -key server.key -out server.csr - -cp server.key server.key.orig - -openssl rsa -in server.key.orig -out server.key - -openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt - -cp server.crt server.pem -cat server.key >> server.pem - -openssl pkcs12 -export -inkey server.key -in server.pem -name ServerName -out server.pfx diff --git a/ceph/src/civetweb/resources/cert/make_certs.bat b/ceph/src/civetweb/resources/cert/make_certs.bat new file mode 100644 index 000000000..66a091d37 --- /dev/null +++ b/ceph/src/civetweb/resources/cert/make_certs.bat @@ -0,0 +1,55 @@ +@echo off +REM We need admin rights, otherwise the random state cannot be written +REM Thanks to http://stackoverflow.com/a/10052222/1531708 + +:: BatchGotAdmin +:------------------------------------- +REM --> Check for permissions + IF "%PROCESSOR_ARCHITECTURE%" EQU "amd64" ( +>nul 2>&1 "%SYSTEMROOT%\SysWOW64\cacls.exe" "%SYSTEMROOT%\SysWOW64\config\system" +) ELSE ( +>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system" +) + +REM --> If error flag set, we do not have admin. +if '%errorlevel%' NEQ '0' ( + echo Requesting administrative privileges... + goto UACPrompt +) else ( goto gotAdmin ) + +:UACPrompt + echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs" + set params = %*:"="" + echo UAC.ShellExecute "cmd.exe", "/c ""%~s0"" %params%", "", "runas", 1 >> "%temp%\getadmin.vbs" + + "%temp%\getadmin.vbs" + del "%temp%\getadmin.vbs" + exit /B + +:gotAdmin + pushd "%CD%" + CD /D "%~dp0" +:-------------------------------------- + +del server.* + +c:\OpenSSL-Win32\bin\openssl.exe genrsa -des3 -out server.key 4096 + +c:\OpenSSL-Win32\bin\openssl.exe req -sha256 -new -key server.key -out server.csr -utf8 + +copy server.key server.key.orig + +c:\OpenSSL-Win32\bin\openssl.exe rsa -in server.key.orig -out server.key + +echo [ v3_ca ] > server.ext.txt +echo [ req ] >> server.ext.txt +echo req_extensions = my_extensions >> server.ext.txt +echo [ my_extensions ] >> server.ext.txt +echo extendedKeyUsage=serverAuth >> server.ext.txt +echo crlDistributionPoints=URI:http://localhost/crl.pem >> server.ext.txt + +c:\OpenSSL-Win32\bin\openssl.exe x509 -req -days 365 -extensions v3_ca -extfile server.ext.txt -in server.csr -signkey server.key -out server.crt + +copy server.crt server.pem + +type server.key >> server.pem diff --git a/ceph/src/civetweb/resources/cert/make_certs.sh b/ceph/src/civetweb/resources/cert/make_certs.sh new file mode 100644 index 000000000..b4b6714cc --- /dev/null +++ b/ceph/src/civetweb/resources/cert/make_certs.sh @@ -0,0 +1,64 @@ +#!/bin/sh +#using "pass" for every password + +echo "Generating client certificate ..." + +openssl genrsa -des3 -out client.key 2048 +openssl req -new -key client.key -out client.csr + +cp client.key client.key.orig + +openssl rsa -in client.key.orig -out client.key + +openssl x509 -req -days 3650 -in client.csr -signkey client.key -out client.crt + +cp client.crt client.pem +cat client.key >> client.pem + +openssl pkcs12 -export -inkey client.key -in client.pem -name ClientName -out client.pfx + + +echo "Generating first server certificate ..." + +openssl genrsa -des3 -out server.key 2048 +openssl req -new -key server.key -out server.csr + +cp server.key server.key.orig + +openssl rsa -in server.key.orig -out server.key + +openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt + +cp server.crt server.pem +cat server.key >> server.pem + +openssl pkcs12 -export -inkey server.key -in server.pem -name ServerName -out server.pfx + +echo "First server certificate hash for Public-Key-Pins header:" + +openssl x509 -pubkey < server.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 > server.pin + +cat server.pin + +echo "Generating backup server certificate ..." + +openssl genrsa -des3 -out server_bkup.key 2048 +openssl req -new -key server_bkup.key -out server_bkup.csr + +cp server_bkup.key server_bkup.key.orig + +openssl rsa -in server_bkup.key.orig -out server_bkup.key + +openssl x509 -req -days 3650 -in server_bkup.csr -signkey server_bkup.key -out server_bkup.crt + +cp server_bkup.crt server_bkup.pem +cat server_bkup.key >> server_bkup.pem + +openssl pkcs12 -export -inkey server_bkup.key -in server_bkup.pem -name ServerName -out server_bkup.pfx + +echo "Backup server certificate hash for Public-Key-Pins header:" + +openssl x509 -pubkey < server_bkup.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 > server_bkup.pin + +cat server_bkup.pin + diff --git a/ceph/src/civetweb/resources/cert/server.crt b/ceph/src/civetweb/resources/cert/server.crt index e74e1830b..a13fa015a 100644 --- a/ceph/src/civetweb/resources/cert/server.crt +++ b/ceph/src/civetweb/resources/cert/server.crt @@ -1,14 +1,19 @@ -----BEGIN CERTIFICATE----- -MIICOTCCAaICCQCWJSBNug1UmTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJ4 -eDELMAkGA1UECAwCeHgxCzAJBgNVBAcMAnh4MQswCQYDVQQKDAJ4eDELMAkGA1UE -CwwCeHgxCzAJBgNVBAMMAnh4MREwDwYJKoZIhvcNAQkBFgJ4eDAeFw0xNTEwMjUy -MzMyMTVaFw0yNTEwMjIyMzMyMTVaMGExCzAJBgNVBAYTAnh4MQswCQYDVQQIDAJ4 -eDELMAkGA1UEBwwCeHgxCzAJBgNVBAoMAnh4MQswCQYDVQQLDAJ4eDELMAkGA1UE -AwwCeHgxETAPBgkqhkiG9w0BCQEWAnh4MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQC+v2d4ye8BgDGncvuCNnJoyt0lcdEiwriGkW7+6eU8CTwgdJGmVZreI9Xo -lDufzcPGtcu5El1XdwlzcaNB+iQuJfXqodvkbw43A80sWtDZuaLVbS9xAr+2mEqC -g4/JYKRDy80y3RZ60S2qvB5jhKb1gjobLe69VXU+aifZtI6LGwIDAQABMA0GCSqG -SIb3DQEBCwUAA4GBAHGVbKEyEIHUYZGGTzmKdQjdeomycKqh0/lgN4LUOFZLpUIb -Ic26ZAWL3x571i05qz90AFUXEx30o0aVRYjvtSDyIlID4Niz9Cy8s8vNIDSocEAG -bzBQ9xgFYjMEcgm2ROkzE6xdyxNOHkPA4jXjqgQknyvtkHcPE7mpv7faZXFz +MIIDBjCCAe4CCQDDIH/hK1C0BjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE3MDkwMzE5MjIyOVoXDTI3MDkwMTE5MjIyOVowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALUmHEoJcebkUOyqEAhH2OdEuTTk8AxjjVvq9B1dXjlf/dvxGnZX2InScGCJA9Uy +kO1XI8nLXKAGl6OL9jDt/0K3/oFLedDLtZf1qE+kEBuaqAgL+VVAPqwtQZcyCoI9 +zx777I1tPUOl1Q1ass3T7lYsTN8QADmW5zjJn4MJPMQ55qoQUL7HVQR4VJ/ELAXu +xGkQlJFBY5q0Qq6buN102D2upNKXKpDYYPc0OgyJ73fR2+rzQapc52QD4Oh6cbD8 +Fh5Vh/qGNMckh1cQsVm6fRtlkoUqxANZk58rqkEwOuk04p7vlnVvZTidOng7G2nW +1n7YQXCycI+JhofCqOqT9x8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEATx5GZCxU +KKQCDsafzAwoodbjRlpsJhvdCBGpgMrFTPyQo7BNF/E2XyVCDXbCmbxTRlhFafJG +Loj/73toGkU8+1qUIy/Fffsmeh9YCyMlA2bE+85ccMCVKgCIEx0+fa6Au6/Ref7/ +n7vN/9deJzxWUaNbP26LNq3prbuIbKN6WFNT5mR8HLTmP3O45sqy1jwOZgSwvbgH +bhugE4tSsKghMV5rUgiMhGIrEakFH+1LCZjQh+ojcWWEWyVk3QTQMmSd6tAZf4pb +/Y1GuN6DAiLfzbabUQZCeQ1iZcgrwIOGHWJUPAf+BTPcFLlR3k/kYA9lrqvra7ln +dFIuUv3YzfenfA== -----END CERTIFICATE----- diff --git a/ceph/src/civetweb/resources/cert/server.csr b/ceph/src/civetweb/resources/cert/server.csr index 7b74b8679..fe5f3fc80 100644 --- a/ceph/src/civetweb/resources/cert/server.csr +++ b/ceph/src/civetweb/resources/cert/server.csr @@ -1,11 +1,16 @@ -----BEGIN CERTIFICATE REQUEST----- -MIIBoTCCAQoCAQAwYTELMAkGA1UEBhMCeHgxCzAJBgNVBAgMAnh4MQswCQYDVQQH -DAJ4eDELMAkGA1UECgwCeHgxCzAJBgNVBAsMAnh4MQswCQYDVQQDDAJ4eDERMA8G -CSqGSIb3DQEJARYCeHgwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL6/Z3jJ -7wGAMady+4I2cmjK3SVx0SLCuIaRbv7p5TwJPCB0kaZVmt4j1eiUO5/Nw8a1y7kS -XVd3CXNxo0H6JC4l9eqh2+RvDjcDzSxa0Nm5otVtL3ECv7aYSoKDj8lgpEPLzTLd -FnrRLaq8HmOEpvWCOhst7r1VdT5qJ9m0josbAgMBAAGgADANBgkqhkiG9w0BAQsF -AAOBgQC3a+xFpygFx3Guq9XRZSbkNX2BlktaKD45qU51E0Ayt75T8iXnpeJV2Y1z -2zjJBPWePdsa6vvHl/gx5oCyHfr8Vzs7AIojtcbKltWesdoJMuhbhPC7434vnYYm -fFXzVcrfuCx6V9YGlbgtGYmItUxyvkmML00XRO7+MJy64aQiCg== +MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALUmHEoJcebkUOyqEAhH2OdEuTTk8AxjjVvq9B1d +Xjlf/dvxGnZX2InScGCJA9UykO1XI8nLXKAGl6OL9jDt/0K3/oFLedDLtZf1qE+k +EBuaqAgL+VVAPqwtQZcyCoI9zx777I1tPUOl1Q1ass3T7lYsTN8QADmW5zjJn4MJ +PMQ55qoQUL7HVQR4VJ/ELAXuxGkQlJFBY5q0Qq6buN102D2upNKXKpDYYPc0OgyJ +73fR2+rzQapc52QD4Oh6cbD8Fh5Vh/qGNMckh1cQsVm6fRtlkoUqxANZk58rqkEw +Ouk04p7vlnVvZTidOng7G2nW1n7YQXCycI+JhofCqOqT9x8CAwEAAaAAMA0GCSqG +SIb3DQEBCwUAA4IBAQCbJgy8LBoI+XCliwPGVM+ZuxEVuR15iaUSX7epuKb4jvyC +y2+YQnNyxLkK8Bu2z9uxXUBbmhqXNiXZd7/SnbTR9MGMq3vyYg6Ggypo24DWez04 +tFaUiLJZsKVoVM6DP3zwpaKKSSJILU2GbNQKW87PHIPSdmAEh+gFD2Uy5sFrvuFJ +LtHfIMMAhMSoEMjmjaLI7N4GVgFhGEr5q5HGpLuAU8cKGyKPkIkSyYN5Ott4u22d +rpASF3TXfCJJ0YiM84U86rhZ0BrMqrVtw8r3uj+4G7hrE92eBU+DDn1D8jWzbyVc +6dlTZaknMeJqsQe2/vq+T5P2yl+/39TnlvDO+cS2 -----END CERTIFICATE REQUEST----- diff --git a/ceph/src/civetweb/resources/cert/server.key b/ceph/src/civetweb/resources/cert/server.key index 596659fbf..bd010effb 100644 --- a/ceph/src/civetweb/resources/cert/server.key +++ b/ceph/src/civetweb/resources/cert/server.key @@ -1,15 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQC+v2d4ye8BgDGncvuCNnJoyt0lcdEiwriGkW7+6eU8CTwgdJGm -VZreI9XolDufzcPGtcu5El1XdwlzcaNB+iQuJfXqodvkbw43A80sWtDZuaLVbS9x -Ar+2mEqCg4/JYKRDy80y3RZ60S2qvB5jhKb1gjobLe69VXU+aifZtI6LGwIDAQAB -AoGBAJkeyzASYhNBVhrGWZGopWTr3GSPnkOaLkiP/JsTJVpxS1v+V2E//Obvu2pN -fCOHKO6dxyEU1es9ek+63EQ9ScaCaaZtqyi8NcttRTXYFcXwl7OZx6DnKSIa7mZA -Z1HFzpZAlCqbh3gf1gGeMlJWEK+qxiDkBXq+pGWeOS2BzPDhAkEA6yHbw/YUmFCa -ng1+EPBCkUTCJudiexnPQF+xlhgW68i11V4W5pLpXYt1PfN1qzw57+VgS+lowGIr -Y4BuRWGciwJBAM+tI88SnygdGZUFCp3FQK4/+QUH7tkJvqmhiW0gaIo8yxRzbK7e -wqV3csy4ov9LYH7kVvFE82VvUIpA4f3izbECQH4EY3gfBuKrMHLM4GfLnKGmrDeV -gx5essjZgJ/kwUQVCf8UsklZK2FLQMa3GLVxTcvYr0eADPgupPpq9q6QpgkCQQCt -ksFGFgNN7JxwD4mi+bUorjE8Qjgf0GQ5tNh+i8K0H0GAs0QYF/jJgT9C2eLpyx84 -jzIXbxCbK+E93CLGJuTRAkEA4LdI5JSUMX4IxVHSsfsHYT4kP3XmONlDW/TzWfK2 -jyDiFOS7lfIe08zeSxdxdpF4y9Y1eGKOjls5y5u7KtV2ug== +MIIEpAIBAAKCAQEAtSYcSglx5uRQ7KoQCEfY50S5NOTwDGONW+r0HV1eOV/92/Ea +dlfYidJwYIkD1TKQ7VcjyctcoAaXo4v2MO3/Qrf+gUt50Mu1l/WoT6QQG5qoCAv5 +VUA+rC1BlzIKgj3PHvvsjW09Q6XVDVqyzdPuVixM3xAAOZbnOMmfgwk8xDnmqhBQ +vsdVBHhUn8QsBe7EaRCUkUFjmrRCrpu43XTYPa6k0pcqkNhg9zQ6DInvd9Hb6vNB +qlznZAPg6HpxsPwWHlWH+oY0xySHVxCxWbp9G2WShSrEA1mTnyuqQTA66TTinu+W +dW9lOJ06eDsbadbWfthBcLJwj4mGh8Ko6pP3HwIDAQABAoIBAGgaacGGogW+Cl+n +8CTCHX3y+bjTJL0J7S/426eQg9jXOI3QhpOiMlgqLtjbhO9d6vnqzS9oBmgUwcqE +YcyGyd5u3P0zAeOjXk3hKIP0Vil2/L/7GaQLkrjiHUKlyHJG0SQORUiVkdKxl7nf ++Mfe1qaBOQAsMuTluyXggSIOCfT+FdHoi6nr/+Nugyx7e/UrZ3GWHVbh8KXOlvHh +kETfcI6KUkWKtE+YJx9w89Bjh8TBvU0nkOntR11T2SMNllyIS9nND8pqa7QPz3N0 +Ag/iN4Wh8S5f4Nn4GccAOtIORuYuw9Pmt1E9dFWEna1fGztBHlClFQPOLUhZ+/zR +MfQV5bkCgYEA3pQTLZ5ldX1Kvg5sYw63wwewr147R0pav6AoJ8HTnWGqi5y485CX +uKE/IcJseidG9FmkO7rfexQaBtW9eW0GCVru416VSP9g2r1iUu0ViaqctYt7ZacE +UEI+g4FmaXHyn1CKTjJXgUAdoDbtlyHwLmLmNt+B3zKGa1lPIb5MwdMCgYEA0Fl7 +VCTnmdyFH8m/bK76uW7SgkYmKYd5AvDr2QFCSqY3tdZh2VIukoUPmheCFq0kpDc0 ++eT680rF/m6CCu+00nM6v/3TNARRANeQ2G73kTPpyiphE+ttKCBQ/tke3TcHQA85 +7cI6bfkMonyKi0JRdLs4QEWf86Avr6p6JKdQWgUCgYEA3oAT8+SF9D89umRcwWFz +HcnQPF7sz0VrFmiZ+7RtQMTjYhFXalQ+91hp7euX2TzuV1JNNVCIG1dq9S4x7PKp +uCxo5m4kugZg4gm0AsXyY95kLa+zuViOnVS7fWab5Aj+y3gN6kG07AYWF5URSaWp +nhVLocso3uB5M1LiIg9EV/UCgYBNrN6Wyz9xFE6pQDzWlxGwakme+eomV3RdDVbQ +S3DchcWFTEykicgFJghgCV2deKWNd2uPsreAVqMkLSzcSOuf/gesJkREQ0uzxaoh +lpVDlBgYH96bX40NhabMrEOec3KHhmWxZ1UDRPNZ7JZ2Pp5Bp77b71knqdO9aRAq +dBo3xQKBgQCnxheQbozuzPO/6nixAng1GP1GuuB2bVb4e5Z0+0dt2RfI8+MSqnSL +q9Yr2+p/fJFkVthrOUYwJkMf7ujhK2uNCJ7aKmwHPSIRztNV3UDGFd9wgpj3Pebx +36ahCvDzidTEG+EEra6zPJ1An3KEbPsfXwcy1NVEZ/kFQyzczL0AOw== -----END RSA PRIVATE KEY----- diff --git a/ceph/src/civetweb/resources/cert/server.key.orig b/ceph/src/civetweb/resources/cert/server.key.orig index 7260533ec..e99f08e8f 100644 --- a/ceph/src/civetweb/resources/cert/server.key.orig +++ b/ceph/src/civetweb/resources/cert/server.key.orig @@ -1,18 +1,30 @@ -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,6BB8D380C900AA8B +DEK-Info: DES-EDE3-CBC,9D77FEDB1409D1BC -+p0gAY1fa9vtz8lmaTgJClsSVhD9Aw/SL0raL8w90e3yYFnT948s5xLPxoz+c3V1 -CkdWcatZO72G1VVOlg1NyjYmujBntkvMF4DiAGAg9l/u19wrvYNINurb86uPsZ2P -9S6SlEzIkuRDdnJXXwT/bpgEYoTVIpOQYMjzIcdYbseaYhy7n9uZCXQLgXChjiuf -LNbArHcB5tJC8QK9DCv4iEV6U8udSd85gs2xs4dBs4dz2jpgD3GLpSMd6+LNSNOV -AqWZM6Xa0PtM9Mlz2JkX+misfY5wR2lqs2z6f6JFIZsLjr3buqUJVNXRTcSLZ7A2 -e/RgE8wC3VVX9ij+7yh3dBKNorJF1nLcSkfTt22OXyppbwIwHKI1RYPc6a6GNZEW -ecZlnuHueUc62e8L8lm6dPtJ5Z4SR6hBBqPOBxNxgEGvt7Gc3jPO7SkqmXatVJ2k -S3HI2umA0f3grolkeJGXlaabRb0z+C13nvBSEDog2Sg2uFu3gwEOXsCfI+EaOghp -earIkirAlasVtFGKwUn0eMVLBrsxvr1yz6y7PnY63kTVkh2JPoOQ/hCO+9bfdIvS -7Sa+pbL29OXSNnt/WDsErKcMTPPAstuz0an1Q7dA7G+3FW7UsLWbYh5sMklHiG8L -u5NC4M4/+oqq0Bv/rYROOSmIc7XRbZ38hep2ML9WHC/zdMssSph4lY/TnMNGqSQ/ -wyRmuT0VmLBQFlFvO41YD97yJD5uEsu+dMH0fsfIJ36U2T1YmJEJU5YOfpE/iGdf -2LuFKRU0TMfwiosxi1Geef6RC/9ADaIuda6aIvfMheAZ7b8Xy3vuvQ== +uC330C4tHeQ7HAGqwIlcTtZia9xbCwMAkUn/PJxdsRqk+vZ3NcheeWdSbq9BMioM +06Vl0DtlhfAr4kF/IDhRCkUsLafPFaiDoAiSjZx9xOoCpSdJTe8W19vq6bf9nE1t +WKLR7Ot73E5Qinzpon0ewqia3bDgAgZsE4o99HmXKHghlSPV2we6ROMWn3QfoEfE +tTCIhDrgsrCobrMtDdlzTe6FHACc5nrVloq9LCynuoig2/W1eGS0WVPWMMuo09Qn +UQbjANNSfZcSWZTg1ynCqk74W1X/0hPo2/FpEPIV3K4ZykKbqgB4HIerZ/sJO2LF +g5KtRBtyqj/OsTs+v8i2eEtMYEbz17oJfgL8e2R+AD8QKWjEWrgS5R71LrCgX+v3 ++lOANQi+xIaz45h6StnH52Yl+4iQ4KyaKquJ7ZKRJDfKw41SOSAYCUIkm9AGIqN2 +/WHxfDCaJEN4da890AwmEtzIlVf5TRcJYRpCtxP4kNihrjjQddV+LYdg09nMgcoZ +zVk5eXLh6cg0KzKTDbM3AUmedmrj6R+diyE8zkJKKfStJcejhjTB8KxAIsg+JFFj +tnWUv6dHfPq/K3qbMGqJyuST9pjW9xBiIbscc4HOLmfpJHcClYEbDgPbAqnDp8p9 +nAkI1LFqwpix7rKvFsqWgt8B9TCrxdUqKnDYUNXt/9C1o8ZR8muaH1Jpp8xCjve3 +XpTAMj9HVE/pRkySn8YHvehnMK9+UdCy1sO4RoF5qn881sgetDIoZ/825u4erDVf +Az20D0TZ9wBz+BG0MW8DxdOJmKjpW2ew0RlkG9mcMvKvkcl0XbKFqpF1ZqNQxMTt +Gw1Ef5Hu9j+ijpBKb/4Pk7xeC6OaYdu9NxzYQtpC5aCKXwca8VlykBlPFGrN3eBV +wrsQ+aEv+Cf0bziGHPhili5eNRW8F53LqKF9WdmAAHdOPNZR5PHL8FudNRV77pcY +0bXiY3cHD/YnUpXWZYqU3qDabwtExugImYzLrVg+BSZROwvUYwgKmcrTpx6lJjcv +ntoC26QVKAHhnaclBjGZKl0Q+pYZwR0TxEMPiKLe47TBcYTwj8GNrLk1Lf/VJcaz +lntXsqVjCkwT7cFYfeb8XOvBlrTYQA0LlEHbTn9VTwRiM5O2JB0nzoC2q8LXlzki +wC5AECcUhzh2zpVuLB/FttxPT37a3ibJBkX0UHf7CsPoR/FnEYKL6Bytp6bovUYy +Ed3L/DWdGCB0+tMX0+GBcaxAz/Fqe++Hp9FvZx+ob6k86FC50x2lRPRk3jZmmcCp +W1mub0DK1Pbdh2cutmutbqXF5R2bWpK9lRb5jiSJuQPODTLS5TQjnwVYmqv9qszv +lnJ54HtfrMfKIEqE9mzBfJ4agsHXG2HLrsmRzF6jflleeJddLKqJJ7U8sGjwlJAS +0NIKtWmw5kpRKStbLDX+uGuWLQfM4ITX33fIRlujvbeJcFwtmM4i4sJC1yYYOvLQ +aHV46KNkTVYouKMpJVvGWfXfcV90gbD3pYtkN8YAjswtWoQAnOLFwFJrM0HORkpU +173uMGgOA/EoBhS0XQd6k1+y00JPGky8GSWUEPKDoqX/uZl8POO7VcbAtV41Wkq8 -----END RSA PRIVATE KEY----- diff --git a/ceph/src/civetweb/resources/cert/server.pem b/ceph/src/civetweb/resources/cert/server.pem index f48a239d9..9a0027c17 100644 --- a/ceph/src/civetweb/resources/cert/server.pem +++ b/ceph/src/civetweb/resources/cert/server.pem @@ -1,29 +1,46 @@ -----BEGIN CERTIFICATE----- -MIICOTCCAaICCQCWJSBNug1UmTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJ4 -eDELMAkGA1UECAwCeHgxCzAJBgNVBAcMAnh4MQswCQYDVQQKDAJ4eDELMAkGA1UE -CwwCeHgxCzAJBgNVBAMMAnh4MREwDwYJKoZIhvcNAQkBFgJ4eDAeFw0xNTEwMjUy -MzMyMTVaFw0yNTEwMjIyMzMyMTVaMGExCzAJBgNVBAYTAnh4MQswCQYDVQQIDAJ4 -eDELMAkGA1UEBwwCeHgxCzAJBgNVBAoMAnh4MQswCQYDVQQLDAJ4eDELMAkGA1UE -AwwCeHgxETAPBgkqhkiG9w0BCQEWAnh4MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQC+v2d4ye8BgDGncvuCNnJoyt0lcdEiwriGkW7+6eU8CTwgdJGmVZreI9Xo -lDufzcPGtcu5El1XdwlzcaNB+iQuJfXqodvkbw43A80sWtDZuaLVbS9xAr+2mEqC -g4/JYKRDy80y3RZ60S2qvB5jhKb1gjobLe69VXU+aifZtI6LGwIDAQABMA0GCSqG -SIb3DQEBCwUAA4GBAHGVbKEyEIHUYZGGTzmKdQjdeomycKqh0/lgN4LUOFZLpUIb -Ic26ZAWL3x571i05qz90AFUXEx30o0aVRYjvtSDyIlID4Niz9Cy8s8vNIDSocEAG -bzBQ9xgFYjMEcgm2ROkzE6xdyxNOHkPA4jXjqgQknyvtkHcPE7mpv7faZXFz +MIIDBjCCAe4CCQDDIH/hK1C0BjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE3MDkwMzE5MjIyOVoXDTI3MDkwMTE5MjIyOVowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALUmHEoJcebkUOyqEAhH2OdEuTTk8AxjjVvq9B1dXjlf/dvxGnZX2InScGCJA9Uy +kO1XI8nLXKAGl6OL9jDt/0K3/oFLedDLtZf1qE+kEBuaqAgL+VVAPqwtQZcyCoI9 +zx777I1tPUOl1Q1ass3T7lYsTN8QADmW5zjJn4MJPMQ55qoQUL7HVQR4VJ/ELAXu +xGkQlJFBY5q0Qq6buN102D2upNKXKpDYYPc0OgyJ73fR2+rzQapc52QD4Oh6cbD8 +Fh5Vh/qGNMckh1cQsVm6fRtlkoUqxANZk58rqkEwOuk04p7vlnVvZTidOng7G2nW +1n7YQXCycI+JhofCqOqT9x8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEATx5GZCxU +KKQCDsafzAwoodbjRlpsJhvdCBGpgMrFTPyQo7BNF/E2XyVCDXbCmbxTRlhFafJG +Loj/73toGkU8+1qUIy/Fffsmeh9YCyMlA2bE+85ccMCVKgCIEx0+fa6Au6/Ref7/ +n7vN/9deJzxWUaNbP26LNq3prbuIbKN6WFNT5mR8HLTmP3O45sqy1jwOZgSwvbgH +bhugE4tSsKghMV5rUgiMhGIrEakFH+1LCZjQh+ojcWWEWyVk3QTQMmSd6tAZf4pb +/Y1GuN6DAiLfzbabUQZCeQ1iZcgrwIOGHWJUPAf+BTPcFLlR3k/kYA9lrqvra7ln +dFIuUv3YzfenfA== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQC+v2d4ye8BgDGncvuCNnJoyt0lcdEiwriGkW7+6eU8CTwgdJGm -VZreI9XolDufzcPGtcu5El1XdwlzcaNB+iQuJfXqodvkbw43A80sWtDZuaLVbS9x -Ar+2mEqCg4/JYKRDy80y3RZ60S2qvB5jhKb1gjobLe69VXU+aifZtI6LGwIDAQAB -AoGBAJkeyzASYhNBVhrGWZGopWTr3GSPnkOaLkiP/JsTJVpxS1v+V2E//Obvu2pN -fCOHKO6dxyEU1es9ek+63EQ9ScaCaaZtqyi8NcttRTXYFcXwl7OZx6DnKSIa7mZA -Z1HFzpZAlCqbh3gf1gGeMlJWEK+qxiDkBXq+pGWeOS2BzPDhAkEA6yHbw/YUmFCa -ng1+EPBCkUTCJudiexnPQF+xlhgW68i11V4W5pLpXYt1PfN1qzw57+VgS+lowGIr -Y4BuRWGciwJBAM+tI88SnygdGZUFCp3FQK4/+QUH7tkJvqmhiW0gaIo8yxRzbK7e -wqV3csy4ov9LYH7kVvFE82VvUIpA4f3izbECQH4EY3gfBuKrMHLM4GfLnKGmrDeV -gx5essjZgJ/kwUQVCf8UsklZK2FLQMa3GLVxTcvYr0eADPgupPpq9q6QpgkCQQCt -ksFGFgNN7JxwD4mi+bUorjE8Qjgf0GQ5tNh+i8K0H0GAs0QYF/jJgT9C2eLpyx84 -jzIXbxCbK+E93CLGJuTRAkEA4LdI5JSUMX4IxVHSsfsHYT4kP3XmONlDW/TzWfK2 -jyDiFOS7lfIe08zeSxdxdpF4y9Y1eGKOjls5y5u7KtV2ug== +MIIEpAIBAAKCAQEAtSYcSglx5uRQ7KoQCEfY50S5NOTwDGONW+r0HV1eOV/92/Ea +dlfYidJwYIkD1TKQ7VcjyctcoAaXo4v2MO3/Qrf+gUt50Mu1l/WoT6QQG5qoCAv5 +VUA+rC1BlzIKgj3PHvvsjW09Q6XVDVqyzdPuVixM3xAAOZbnOMmfgwk8xDnmqhBQ +vsdVBHhUn8QsBe7EaRCUkUFjmrRCrpu43XTYPa6k0pcqkNhg9zQ6DInvd9Hb6vNB +qlznZAPg6HpxsPwWHlWH+oY0xySHVxCxWbp9G2WShSrEA1mTnyuqQTA66TTinu+W +dW9lOJ06eDsbadbWfthBcLJwj4mGh8Ko6pP3HwIDAQABAoIBAGgaacGGogW+Cl+n +8CTCHX3y+bjTJL0J7S/426eQg9jXOI3QhpOiMlgqLtjbhO9d6vnqzS9oBmgUwcqE +YcyGyd5u3P0zAeOjXk3hKIP0Vil2/L/7GaQLkrjiHUKlyHJG0SQORUiVkdKxl7nf ++Mfe1qaBOQAsMuTluyXggSIOCfT+FdHoi6nr/+Nugyx7e/UrZ3GWHVbh8KXOlvHh +kETfcI6KUkWKtE+YJx9w89Bjh8TBvU0nkOntR11T2SMNllyIS9nND8pqa7QPz3N0 +Ag/iN4Wh8S5f4Nn4GccAOtIORuYuw9Pmt1E9dFWEna1fGztBHlClFQPOLUhZ+/zR +MfQV5bkCgYEA3pQTLZ5ldX1Kvg5sYw63wwewr147R0pav6AoJ8HTnWGqi5y485CX +uKE/IcJseidG9FmkO7rfexQaBtW9eW0GCVru416VSP9g2r1iUu0ViaqctYt7ZacE +UEI+g4FmaXHyn1CKTjJXgUAdoDbtlyHwLmLmNt+B3zKGa1lPIb5MwdMCgYEA0Fl7 +VCTnmdyFH8m/bK76uW7SgkYmKYd5AvDr2QFCSqY3tdZh2VIukoUPmheCFq0kpDc0 ++eT680rF/m6CCu+00nM6v/3TNARRANeQ2G73kTPpyiphE+ttKCBQ/tke3TcHQA85 +7cI6bfkMonyKi0JRdLs4QEWf86Avr6p6JKdQWgUCgYEA3oAT8+SF9D89umRcwWFz +HcnQPF7sz0VrFmiZ+7RtQMTjYhFXalQ+91hp7euX2TzuV1JNNVCIG1dq9S4x7PKp +uCxo5m4kugZg4gm0AsXyY95kLa+zuViOnVS7fWab5Aj+y3gN6kG07AYWF5URSaWp +nhVLocso3uB5M1LiIg9EV/UCgYBNrN6Wyz9xFE6pQDzWlxGwakme+eomV3RdDVbQ +S3DchcWFTEykicgFJghgCV2deKWNd2uPsreAVqMkLSzcSOuf/gesJkREQ0uzxaoh +lpVDlBgYH96bX40NhabMrEOec3KHhmWxZ1UDRPNZ7JZ2Pp5Bp77b71knqdO9aRAq +dBo3xQKBgQCnxheQbozuzPO/6nixAng1GP1GuuB2bVb4e5Z0+0dt2RfI8+MSqnSL +q9Yr2+p/fJFkVthrOUYwJkMf7ujhK2uNCJ7aKmwHPSIRztNV3UDGFd9wgpj3Pebx +36ahCvDzidTEG+EEra6zPJ1An3KEbPsfXwcy1NVEZ/kFQyzczL0AOw== -----END RSA PRIVATE KEY----- diff --git a/ceph/src/civetweb/resources/cert/server.pfx b/ceph/src/civetweb/resources/cert/server.pfx deleted file mode 100644 index e334a6a59..000000000 Binary files a/ceph/src/civetweb/resources/cert/server.pfx and /dev/null differ diff --git a/ceph/src/civetweb/resources/cert/server.pin b/ceph/src/civetweb/resources/cert/server.pin new file mode 100644 index 000000000..015792a47 --- /dev/null +++ b/ceph/src/civetweb/resources/cert/server.pin @@ -0,0 +1 @@ +uz1UTAPen+xb+UoQqkVlEx4H653LbMjfRJcZx5OrjbI= diff --git a/ceph/src/civetweb/resources/cert/server_bkup.crt b/ceph/src/civetweb/resources/cert/server_bkup.crt new file mode 100644 index 000000000..afe0d5dd0 --- /dev/null +++ b/ceph/src/civetweb/resources/cert/server_bkup.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe4CCQCFKfFGF1i10TANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE3MDkwMzE5MjI1MVoXDTI3MDkwMTE5MjI1MVowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKTJr3PzWOR1Hrjfk9bBA7TptI1hNYVn/Xvi2GSferhJaWg69b2Li4t5/JxElESR +8fy0lBMzQ/yaFiQb51y7Q1c+Z6xWLxk322rfy3WhU3DYiFL2sJndrDvAhmso122Z +xVADA0cQwo520MgFYpHNBF8BcFV2IRukzVX+/nVkki05XcwfbI2y6gqCRpOSXdE9 +gCDVan3tSRbtrwKu7IHy88mL6057o82Uezpl0KesoCwb4f5oqs2vThUmXKuxu8GO +WpZNK4JFWnTgDOJrubZvKxzzL9E85DS9aXLk6dNKBJVKPCETnYw+2ArMgXzs+JuA +C4AhV0e6unLX9DcavZ6j7JcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAJJWqVuQs +guFZG/LZPeeh1WtZr9S6R5BT4+b+PH2teVyGtClXV6KpwcLNEVWzY3qPtrFFPQI1 +uEg6cY8w1JOiCmj/IWKsiHd+IdsqsFVKL+Bmvthm3HSgA6p6ZiVCG4E67p8xwiJP +p5EwtMM/7BdS/tHLUOe1OpNZ8XtHRVUNbzy/+JV0So7WLP9ksGb6COL/9MF0/qG4 +4XrrvpZ9FAgRC9/22QyYiQqoaegGEy4E+KHOBxRmipInsU2H8aQA2sZzQ49Zew9E +QI2jSJTC7EeuZ0OcZawKkJY1ZtIGmOo/Q956keOLdG8cxyq6pXW3gmq1X5QBxy1M +pZYi5eIENGE63g== +-----END CERTIFICATE----- diff --git a/ceph/src/civetweb/resources/cert/server_bkup.csr b/ceph/src/civetweb/resources/cert/server_bkup.csr new file mode 100644 index 000000000..c866b57df --- /dev/null +++ b/ceph/src/civetweb/resources/cert/server_bkup.csr @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKTJr3PzWOR1Hrjfk9bBA7TptI1hNYVn/Xvi2GSf +erhJaWg69b2Li4t5/JxElESR8fy0lBMzQ/yaFiQb51y7Q1c+Z6xWLxk322rfy3Wh +U3DYiFL2sJndrDvAhmso122ZxVADA0cQwo520MgFYpHNBF8BcFV2IRukzVX+/nVk +ki05XcwfbI2y6gqCRpOSXdE9gCDVan3tSRbtrwKu7IHy88mL6057o82Uezpl0Kes +oCwb4f5oqs2vThUmXKuxu8GOWpZNK4JFWnTgDOJrubZvKxzzL9E85DS9aXLk6dNK +BJVKPCETnYw+2ArMgXzs+JuAC4AhV0e6unLX9DcavZ6j7JcCAwEAAaAAMA0GCSqG +SIb3DQEBCwUAA4IBAQBvbql7sAA8XOwsszRUzOCLkFxfDsWJ0l5re2mGgHTEd5hc +eDfM+Vdy8SVZX9OySdioVD6ACTse3rc1ULYn8jj1wvOd3/z/J9aUBcBACJG5D1Dl ++j+xvfhvgAGCEQn7ZMaWLFWrLs++aQ+EKbl0SypEI2rTJkyZlYSDVpa+LhqX4UOa ++RNlq1CX+85HCjBn0sWBNzhjrf3gwERRn5NfTab4FqwqGp2+s4GvbOJHrm8saMWu +BlhcTzGGLBRKCQUHo5i9393b3oBOqtcpWPcZGhyAF1NUbYL7USnsiH6lkGReeaFi +xy7vYmUn9j//vT64SmASG0oF+ecUF0q2W42sSqnU +-----END CERTIFICATE REQUEST----- diff --git a/ceph/src/civetweb/resources/cert/server_bkup.key b/ceph/src/civetweb/resources/cert/server_bkup.key new file mode 100644 index 000000000..235c83a79 --- /dev/null +++ b/ceph/src/civetweb/resources/cert/server_bkup.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEApMmvc/NY5HUeuN+T1sEDtOm0jWE1hWf9e+LYZJ96uElpaDr1 +vYuLi3n8nESURJHx/LSUEzND/JoWJBvnXLtDVz5nrFYvGTfbat/LdaFTcNiIUvaw +md2sO8CGayjXbZnFUAMDRxDCjnbQyAVikc0EXwFwVXYhG6TNVf7+dWSSLTldzB9s +jbLqCoJGk5Jd0T2AINVqfe1JFu2vAq7sgfLzyYvrTnujzZR7OmXQp6ygLBvh/miq +za9OFSZcq7G7wY5alk0rgkVadOAM4mu5tm8rHPMv0TzkNL1pcuTp00oElUo8IROd +jD7YCsyBfOz4m4ALgCFXR7q6ctf0Nxq9nqPslwIDAQABAoIBAE/B7lHIrnWk2kHQ +tNV0hj7B/smPC0COnHmhyeqp5dPcdFAmeVpMeDYBzOo1py2pFd6h6CmC3p0cVysS +9mBDosxPQA6BiDpEdsa7mtZMRv6PTywYilFuoTYqcOTc16gMjRu02ZlD22boyxSE +xria6kqxf5Vdn5ipo1jEGpTnIHkSS+Y8CetCaYgcezLaXlXN3RyjF6tCHMeS3iLl +/zY2O4avG2BM+vvDGDW2FWtZg+hN+5Yk90Qt8dFTwvWRCfYaSWfi7id91p5X0rnL +x1G07qw18LziKJj4HZiueqbDcDOYhfcA6sd0OHcvtXfGIoeqkXxi54cIOReRhN2/ +7ib3iUECgYEA2DNH5aiwc5uqTAL9RHTnuuFwQe46onJwnBkho+xEvvdsp2Q2f7VR +c5M17fL+Rb5gq0O4vzeegKiYpo8gKjFp3Duv9Gdc/TB9sLEEt4NQMD4shV7ihBwC +Rjsflww45dt0mccFZp1ncDYKWHDFzdhO+WB828FPFh/5dl6S+v4Q9bUCgYEAwx+G +XhheTMSqoKGVJ283+4bNZWUSE99wcAhx9J3FkJera030mh0OHoCn0myBjRjxOSY/ +eBH8/0YoLkGYvTdEU/tYiLIWJ/ehC0eweXiwDehb5meco6u9WCeYvyPMLErXbe3K +BQVyfcFzva4eC3dZ7lzxmyVyKXVTYgY0Hf7biJsCgYBKHdJg/eJ3z36jDkdK55Tl +cRFt2MCLHhZSvR7WNlIe8W1zORyhzUP+DhJn32yh9jDnpZC5JNUWoDWsq9ZIAKac +1G1uqNytA6mjIBxQ2RhtYXMbybp3ta5l6zDaNFtxGTmw2hSU6BMk2bHUPdzhw2zX +eudy4qM9H3sCxEs49k5UHQKBgDz7I0FRGFehtznQhg73AWYIsTSZK9cuI7O/z+2F +SXNxE0/L40AvCHSb/NcUtkBkpS8ZNwjNhmY5hOE/+v5XwXEFwpumHKqNB7XAx/SO +tWcDUYVmqFu2lsxwQ5qpE2xcT4u5n0OGeku3I/cJ7bXjrSWDwracM1uloVOnYK5n +MjE1AoGAeM6Wrb0VXRq025+OEfoFis3P9S0REkkkabM9+VLRSWi63uxg2cyipxUg +qJUThbUm1aSS1F+XWjG7vrDjWT/GQTYj9/CH3mZRflZgLUltVHEZesLwWqn15Gl/ +BDwaV6RN7F3BCSzgEfCutrfGJqxA0tx5TTcupOgwpZVakN+hm3c= +-----END RSA PRIVATE KEY----- diff --git a/ceph/src/civetweb/resources/cert/server_bkup.key.orig b/ceph/src/civetweb/resources/cert/server_bkup.key.orig new file mode 100644 index 000000000..3e227f271 --- /dev/null +++ b/ceph/src/civetweb/resources/cert/server_bkup.key.orig @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,E700A7E4CCCF78FC + +1/jqqjzwHWxdTvayJ+y//FTMuxZbIOT8hl4h+4zzh+/o45RHUa8n6nTI3mLSIK/i +6yZqSaPaCiBINcLWmijbeDN73OhVL3rrum1VotcTUTA2LU0M+kLWpmcJrY5lsku2 +2voulXmLoCniup+nhnGXDWOk3jaLsMBOn3kYyVBgphwzGzKinFQnqzo/w6/2pJ/C +iKb/GWNEuXwHkoTz7A4o1ZVVOQyx8h0klWbwjBEPB+cPE3h/bRTkJWTTy2yfCeUC +nyRQ1BkWC6I5LLesC7gG0jsw3rcGkJnu+zNkxG43N9CkU74S/jNwktjqzKiSbO14 +SYu/NiaVLCtQTeaTeh39X8OGW4RzFbO32PVBl0jL5d8h3DpvTufbtC9BS9dADM0o +pwCUVWiKKgApmqhFDyUpQB8ptfLewmp5ksB93NzdlPLV8vojJ7nBOrppaueXKQ6Z +f380J3xCrVN7pTt/yT3mlvCnmb0gNhL6jAE53C112Upjmu40OBhwjGDjDXsOZBmZ +NH0KEsLecIPgbx0W27h0j4JDdXGtI4mjFHHEnFj75We73BZ8BIlyRt7nxS+iFYNH +hpbwuNc4dX953jwPy7CIxyms5cy4BigTv/rsgFWCxWxFcTqYkp6L3z8IC6apJDSp +htKLzhFKjlXqP3vcwZYrAF26eOl6Pxn74853dRskAZNY5F40/7IjVb8l71tedWof +WE5wpuXrZJd+GBeIM+plbPCnBiNSHuRzJPhLU3tsT3X70WfDxgIgM38P5uOOBLma +hU/0wcL8+Q3HESPx5ju+5lYZBmozs5ANwMggXv0a1vBptI/kA0HeMQx52G4m1F+9 +aYRrNc+Exl901Yjn120Y6NllIk5EolsqNifDsems9sTiC91Fvh7yiYI5Pd7qCwoR +2ssLbWda/+bgqtDXjmv4x1btWhWmbInBpCrp1YEwILlyNN6FQ/sQ8pvHtyC9+FcB +xQ7wI0JnsCpj8E+P5C08EEgpTiUfelwYyTZLarAFMRe5HWZjgQW7+JvbiQ4Q3ZXM +/DaYh6zGXvR4OomTqKN63i6iAckS7Uh3/XzaWbjOAxvMIgKhU7OBqDAlPvgXJh1y +sDig2zTR603AURkWZir2OOr7XKZcqNj8lxt+BG+E6bwxdeIeEQn7f8Ef5oUmFNXQ +o5zQwI12RDQXaBRDG/wTONrUhvc8TEM04jNGKMRPU6FlZSEF2zlTSU8/QtO56FwR +MwhPlNUSgWgvqzFWoA4W7XWjAfYqvoVRcLjcZF2WBUJwYq4ZODNqBH+j3+Ftge9l +wKc/9KjcurpAWbg7gq9XtwgiT8bYHcM3NSOwgnrOJ4wtukuwbLq2JjMLgFQeDAev +NFJfbYoZ0iTyIq1WRS0MlhAwDKujDOoQLqkF41LC5Ac6RpMeR689xN18YE6b6iXp +f93tHI+6Ru1I+2ZoGbvCPmasv3jk69C8A/StmUEcFfxmOr5qhQEVR2pIXfXKeqbE +KCUoR4Wax42q/bDhgIOOmq+E9YsTuy4Iq5J25WDIbgWN35s0qXDm91s+aY0KtDUu +fxGdOIHQHx10ARHUKZ6AhXSF+q5QQFy4ejlgiTMorvT0XUHmIQ82hw== +-----END RSA PRIVATE KEY----- diff --git a/ceph/src/civetweb/resources/cert/server_bkup.pem b/ceph/src/civetweb/resources/cert/server_bkup.pem new file mode 100644 index 000000000..a409c1435 --- /dev/null +++ b/ceph/src/civetweb/resources/cert/server_bkup.pem @@ -0,0 +1,46 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe4CCQCFKfFGF1i10TANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE3MDkwMzE5MjI1MVoXDTI3MDkwMTE5MjI1MVowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKTJr3PzWOR1Hrjfk9bBA7TptI1hNYVn/Xvi2GSferhJaWg69b2Li4t5/JxElESR +8fy0lBMzQ/yaFiQb51y7Q1c+Z6xWLxk322rfy3WhU3DYiFL2sJndrDvAhmso122Z +xVADA0cQwo520MgFYpHNBF8BcFV2IRukzVX+/nVkki05XcwfbI2y6gqCRpOSXdE9 +gCDVan3tSRbtrwKu7IHy88mL6057o82Uezpl0KesoCwb4f5oqs2vThUmXKuxu8GO +WpZNK4JFWnTgDOJrubZvKxzzL9E85DS9aXLk6dNKBJVKPCETnYw+2ArMgXzs+JuA +C4AhV0e6unLX9DcavZ6j7JcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAJJWqVuQs +guFZG/LZPeeh1WtZr9S6R5BT4+b+PH2teVyGtClXV6KpwcLNEVWzY3qPtrFFPQI1 +uEg6cY8w1JOiCmj/IWKsiHd+IdsqsFVKL+Bmvthm3HSgA6p6ZiVCG4E67p8xwiJP +p5EwtMM/7BdS/tHLUOe1OpNZ8XtHRVUNbzy/+JV0So7WLP9ksGb6COL/9MF0/qG4 +4XrrvpZ9FAgRC9/22QyYiQqoaegGEy4E+KHOBxRmipInsU2H8aQA2sZzQ49Zew9E +QI2jSJTC7EeuZ0OcZawKkJY1ZtIGmOo/Q956keOLdG8cxyq6pXW3gmq1X5QBxy1M +pZYi5eIENGE63g== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEApMmvc/NY5HUeuN+T1sEDtOm0jWE1hWf9e+LYZJ96uElpaDr1 +vYuLi3n8nESURJHx/LSUEzND/JoWJBvnXLtDVz5nrFYvGTfbat/LdaFTcNiIUvaw +md2sO8CGayjXbZnFUAMDRxDCjnbQyAVikc0EXwFwVXYhG6TNVf7+dWSSLTldzB9s +jbLqCoJGk5Jd0T2AINVqfe1JFu2vAq7sgfLzyYvrTnujzZR7OmXQp6ygLBvh/miq +za9OFSZcq7G7wY5alk0rgkVadOAM4mu5tm8rHPMv0TzkNL1pcuTp00oElUo8IROd +jD7YCsyBfOz4m4ALgCFXR7q6ctf0Nxq9nqPslwIDAQABAoIBAE/B7lHIrnWk2kHQ +tNV0hj7B/smPC0COnHmhyeqp5dPcdFAmeVpMeDYBzOo1py2pFd6h6CmC3p0cVysS +9mBDosxPQA6BiDpEdsa7mtZMRv6PTywYilFuoTYqcOTc16gMjRu02ZlD22boyxSE +xria6kqxf5Vdn5ipo1jEGpTnIHkSS+Y8CetCaYgcezLaXlXN3RyjF6tCHMeS3iLl +/zY2O4avG2BM+vvDGDW2FWtZg+hN+5Yk90Qt8dFTwvWRCfYaSWfi7id91p5X0rnL +x1G07qw18LziKJj4HZiueqbDcDOYhfcA6sd0OHcvtXfGIoeqkXxi54cIOReRhN2/ +7ib3iUECgYEA2DNH5aiwc5uqTAL9RHTnuuFwQe46onJwnBkho+xEvvdsp2Q2f7VR +c5M17fL+Rb5gq0O4vzeegKiYpo8gKjFp3Duv9Gdc/TB9sLEEt4NQMD4shV7ihBwC +Rjsflww45dt0mccFZp1ncDYKWHDFzdhO+WB828FPFh/5dl6S+v4Q9bUCgYEAwx+G +XhheTMSqoKGVJ283+4bNZWUSE99wcAhx9J3FkJera030mh0OHoCn0myBjRjxOSY/ +eBH8/0YoLkGYvTdEU/tYiLIWJ/ehC0eweXiwDehb5meco6u9WCeYvyPMLErXbe3K +BQVyfcFzva4eC3dZ7lzxmyVyKXVTYgY0Hf7biJsCgYBKHdJg/eJ3z36jDkdK55Tl +cRFt2MCLHhZSvR7WNlIe8W1zORyhzUP+DhJn32yh9jDnpZC5JNUWoDWsq9ZIAKac +1G1uqNytA6mjIBxQ2RhtYXMbybp3ta5l6zDaNFtxGTmw2hSU6BMk2bHUPdzhw2zX +eudy4qM9H3sCxEs49k5UHQKBgDz7I0FRGFehtznQhg73AWYIsTSZK9cuI7O/z+2F +SXNxE0/L40AvCHSb/NcUtkBkpS8ZNwjNhmY5hOE/+v5XwXEFwpumHKqNB7XAx/SO +tWcDUYVmqFu2lsxwQ5qpE2xcT4u5n0OGeku3I/cJ7bXjrSWDwracM1uloVOnYK5n +MjE1AoGAeM6Wrb0VXRq025+OEfoFis3P9S0REkkkabM9+VLRSWi63uxg2cyipxUg +qJUThbUm1aSS1F+XWjG7vrDjWT/GQTYj9/CH3mZRflZgLUltVHEZesLwWqn15Gl/ +BDwaV6RN7F3BCSzgEfCutrfGJqxA0tx5TTcupOgwpZVakN+hm3c= +-----END RSA PRIVATE KEY----- diff --git a/ceph/src/civetweb/resources/cert/server_bkup.pin b/ceph/src/civetweb/resources/cert/server_bkup.pin new file mode 100644 index 000000000..0e0561290 --- /dev/null +++ b/ceph/src/civetweb/resources/cert/server_bkup.pin @@ -0,0 +1 @@ +pf3px1MBPmlTGAPoiHWqaSJ9L9Z+DKfwgsU7LfLnmsk= diff --git a/ceph/src/civetweb/resources/cleanup.lua b/ceph/src/civetweb/resources/cleanup.lua deleted file mode 100644 index ab9557db8..000000000 --- a/ceph/src/civetweb/resources/cleanup.lua +++ /dev/null @@ -1,92 +0,0 @@ --- Lua script used to clean up tabs and spaces in C, CPP and H files. --- Copyright (c) 2014, bel --- MIT License (http://opensource.org/licenses/mit-license.php) --- --- It can be used from the command line: --- Call Lua5.1 or Lua5.2 + this script file + the C/CPP/H file to clean --- --- It can be used in Visual Studio as an external tool: --- command: Lua5.1.exe or Lua5.2.exe --- argument: "X:\civetweb\resources\cleanup.lua" $(ItemPath) --- - -clean = arg[1] -print("Cleaning " .. clean) - -lines = io.lines(clean) -if not lines then - print("Can not open file " .. clean) - return -end - -function trimright(s) - return s:match "^(.-)%s*$" -end - -local lineend = false -local tabspace = false -local changed = false -local invalid = false -local newfile = {} - -lineno = 0 -incmt = false - -for l in lines do - lineno = lineno + 1 - local lt = trimright(l) - if (lt ~= l) then - lineend = true - changed = true - end - local mcmt = l:find("%/%*"); - if mcmt then - if incmt then - print("line " .. lineno .. " nested comment") - end - if not (l:sub(mcmt):find("%*%/")) then - -- multiline comment begins here - incmt = true - end - elseif incmt then - if not l:find("^%s*%*") then - print("line " .. lineno .. " multiline comment without leading *") - end - if l:find("%*%/") then - incmt = false - end - else - local cmt = l:find("//") - if (cmt) and (l:sub(cmt-5, cmt+1) ~= "http://") and (l:sub(cmt-6, cmt+1) ~= "https://") then - print("line " .. lineno .. " has C++ comment //") - end - end - local lts = lt:gsub('\t', ' ') - if (lts ~= lt) then - tabspace = true - changed = true - end - for i=1,#lts do - local b = string.byte(lts,i) - if b<32 or b>=127 then - print("Letter " .. string.byte(l,i) .. " (" .. b .. ") found in line " .. lts) - invalid = true - end - end - - newfile[#newfile + 1] = lts -end - -print("Line endings trimmed: " .. tostring(lineend)) -print("Tabs converted to spaces: " .. tostring(tabspace)) -print("Invalid characters: " .. tostring(invalid)) - -if changed then - local f = io.open(clean, "wb") - for i=1,#newfile do - f:write(newfile[i]) - f:write("\n") - end - f:close() - print("File cleaned") -end diff --git a/ceph/src/civetweb/resources/coverity_check.sh b/ceph/src/civetweb/resources/coverity_check.sh old mode 100644 new mode 100755 index 7cb843967..063d7c8c2 --- a/ceph/src/civetweb/resources/coverity_check.sh +++ b/ceph/src/civetweb/resources/coverity_check.sh @@ -1,5 +1,6 @@ #! /bin/sh +# check if we use the correct directory ls src/civetweb.c if [ "$?" = "0" ]; then echo "Building files for coverity check ..." @@ -9,19 +10,44 @@ else exit 1 fi -rm -rf cov_int/ -make clean +# remove last build +rm -rf cov_build/ -../cov-analysis-linux64-7.6.0/bin/cov-build --dir cov-int make WITH_IPV6=1 WITH_WEBSOCKET=1 WITH_LUA_SHARED=1 +# copy files to build folder +mkdir cov_build +mkdir cov_build/src +mkdir cov_build/include +mkdir cov_build/resources -rm civetweb_coverity_check.tgz +cp Makefile cov_build/ +cp src/*.c cov_build/src/ +cp src/*.inl cov_build/src/ +cp include/civetweb.h cov_build/include/ +cp resources/Makefile.in-os cov_build/resources/ + +cd cov_build + +# new scan build +../../cov-analysis-linux64-8.7.0/bin/cov-build --dir cov-int make WITH_IPV6=1 WITH_WEBSOCKET=1 WITH_SERVER_STATS=1 + + +# pack build results for upload tar czvf civetweb_coverity_check.tgz cov-int +cd .. + +# check if the build was successful echo -ls -la civetweb_coverity_check.tgz +ls -la cov_build/civetweb_coverity_check.tgz if [ "$?" = "0" ]; then echo "... done" + echo + echo "submit to https://scan.coverity.com/projects/bel2125-civetweb" + echo + echo "last commit was" + git log -n 1 + echo echo else echo "No civetweb_coverity_check.tgz file" 1>&2 @@ -29,5 +55,6 @@ else exit 1 fi +# return "ok" exit 0 diff --git a/ceph/src/civetweb/src/CMakeLists.txt b/ceph/src/civetweb/src/CMakeLists.txt index 7c561797c..a0528b287 100644 --- a/ceph/src/civetweb/src/CMakeLists.txt +++ b/ceph/src/civetweb/src/CMakeLists.txt @@ -39,13 +39,17 @@ if (CIVETWEB_ENABLE_WEBSOCKETS AND CIVETWEB_ENABLE_LUA AND LIBRT_FOUND) endif() # We need to link OpenSSL if not dynamically loading -if (CIVETWEB_ENABLE_SLL AND NOT CIVETWEB_ENABLE_OPENSLL_DYNAMIC_LOADING) - find_package(OpenSSL) - target_link_libraries(c-library ${OPENSSL_LIBRARIES}) -else() - find_package(LibDl) - if (LIBDL_FOUND) - target_link_libraries(c-library -ldl) +if (CIVETWEB_ENABLE_SSL) + if (CIVETWEB_ENABLE_SSL_DYNAMIC_LOADING) + find_package(LibDl) + if (LIBDL_FOUND) + target_link_libraries(c-library -ldl) + endif() + else() + find_package(OpenSSL) + include_directories(${OPENSSL_INCLUDE_DIR}) + message(STATUS "OpenSSL include directory: ${OPENSSL_INCLUDE_DIR}") + target_link_libraries(c-library ${OPENSSL_LIBRARIES}) endif() endif() @@ -229,12 +233,14 @@ add_executable(c-executable main.c) set_target_properties(c-executable PROPERTIES OUTPUT_NAME "civetweb" ) -install( - TARGETS c-executable - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin - COMPONENT server) +if (CIVETWEB_INSTALL_EXECUTABLE) + install( + TARGETS c-executable + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + COMPONENT server) +endif() if (BUILD_SHARED_LIBS) target_compile_definitions(c-executable PRIVATE CIVETWEB_DLL_IMPORTS) endif() @@ -261,31 +267,31 @@ if (CIVETWEB_ENABLE_LUA) ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin - COMPONENT lua-library) + COMPONENT lua-library) endif() # The C++ API library if (CIVETWEB_ENABLE_CXX) - add_library(cxx-library CivetServer.cpp) - set_target_properties(cxx-library PROPERTIES - OUTPUT_NAME "cxx-library" + add_library(civetweb-cpp CivetServer.cpp) + set_target_properties(civetweb-cpp PROPERTIES + OUTPUT_NAME "civetweb-cpp" VERSION ${CIVETWEB_VERSION} SOVERSION ${CIVETWEB_VERSION} ) if (BUILD_SHARED_LIBS) - target_compile_definitions(cxx-library PRIVATE CIVETWEB_DLL_EXPORTS) + target_compile_definitions(civetweb-cpp PRIVATE CIVETWEB_DLL_EXPORTS) endif() target_include_directories( - cxx-library PUBLIC + civetweb-cpp PUBLIC ${PROJECT_SOURCE_DIR}/include) install( - TARGETS cxx-library + TARGETS civetweb-cpp ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin - COMPONENT cxx-library) + COMPONENT civetweb-cpp) install(FILES ${PROJECT_SOURCE_DIR}/include/CivetServer.h DESTINATION include - COMPONENT cxx-library) + COMPONENT civetweb-cpp) endif() diff --git a/ceph/src/civetweb/src/CivetServer.cpp b/ceph/src/civetweb/src/CivetServer.cpp index d7d38a5ea..186f18b15 100644 --- a/ceph/src/civetweb/src/CivetServer.cpp +++ b/ceph/src/civetweb/src/CivetServer.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014 the Civetweb developers +/* Copyright (c) 2013-2017 the Civetweb developers * Copyright (c) 2013 No Face Press, LLC * * License http://opensource.org/licenses/mit-license.php MIT License @@ -269,11 +269,14 @@ CivetCallbacks::CivetCallbacks() } CivetServer::CivetServer(const char **options, - const struct CivetCallbacks *_callbacks) + const struct CivetCallbacks *_callbacks, + const void *UserContextIn) : context(0) { struct CivetCallbacks callbacks; + UserContext = UserContextIn; + if (_callbacks) { callbacks = *_callbacks; userCloseHandler = _callbacks->connection_close; @@ -288,11 +291,14 @@ CivetServer::CivetServer(const char **options, } CivetServer::CivetServer(std::vector options, - const struct CivetCallbacks *_callbacks) + const struct CivetCallbacks *_callbacks, + const void *UserContextIn) : context(0) { struct CivetCallbacks callbacks; + UserContext = UserContextIn; + if (_callbacks) { callbacks = *_callbacks; userCloseHandler = _callbacks->connection_close; @@ -321,17 +327,16 @@ CivetServer::~CivetServer() void CivetServer::closeHandler(const struct mg_connection *conn) { - const struct mg_request_info *request_info = mg_get_request_info(conn); - assert(request_info != NULL); - CivetServer *me = (CivetServer *)(request_info->user_data); + CivetServer *me = (CivetServer *)mg_get_user_data(mg_get_context(conn)); assert(me != NULL); // Happens when a request hits the server before the context is saved if (me->context == NULL) return; - if (me->userCloseHandler) + if (me->userCloseHandler) { me->userCloseHandler(conn); + } mg_lock_context(me->context); me->connections.erase(const_cast(conn)); mg_unlock_context(me->context); @@ -574,11 +579,21 @@ CivetServer::urlEncode(const char *src, std::vector CivetServer::getListeningPorts() { - std::vector ports(10); - std::vector ssl(10); - size_t size = mg_get_ports(context, ports.size(), &ports[0], &ssl[0]); + std::vector ports(50); + std::vector server_ports(50); + int size = mg_get_server_ports(context, + (int)server_ports.size(), + &server_ports[0]); + if (size <= 0) { + ports.resize(0); + return ports; + } ports.resize(size); - ssl.resize(size); + server_ports.resize(size); + for (int i = 0; i < size; i++) { + ports[i] = server_ports[i].port; + } + return ports; } diff --git a/ceph/src/civetweb/src/civetweb.c b/ceph/src/civetweb/src/civetweb.c index 26f1edb06..76f097ac1 100644 --- a/ceph/src/civetweb/src/civetweb.c +++ b/ceph/src/civetweb/src/civetweb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016 the Civetweb developers +/* Copyright (c) 2013-2017 the Civetweb developers * Copyright (c) 2004-2013 Sergey Lyubka * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -20,7 +20,6 @@ * THE SOFTWARE. */ - #if defined(_WIN32) #if !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */ @@ -53,7 +52,7 @@ #endif #endif -#if defined(USE_LUA) && defined(USE_WEBSOCKET) +#if defined(USE_LUA) #define USE_TIMERS #endif @@ -95,8 +94,17 @@ mg_static_assert(sizeof(int) == 4 || sizeof(int) == 8, mg_static_assert(sizeof(void *) == 4 || sizeof(void *) == 8, "pointer data type size check"); mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check"); -/* mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "size_t data - * type size check"); */ + + +/* Alternative queue is well tested and should be the new default */ +#ifdef NO_ALTERNATIVE_QUEUE +#ifdef ALTERNATIVE_QUEUE +#error "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE or none, but not both" +#endif +#else +#define ALTERNATIVE_QUEUE +#endif + /* DTL -- including winsock2.h works better if lean and mean */ #ifndef WIN32_LEAN_AND_MEAN @@ -104,21 +112,58 @@ mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check"); #endif #if defined(__SYMBIAN32__) +/* According to https://en.wikipedia.org/wiki/Symbian#History, + * Symbian is no longer maintained since 2014-01-01. + * Recent versions of CivetWeb are no longer tested for Symbian. + * It makes no sense, to support an abandoned operating system. + * All remaining "#ifdef __SYMBIAN__" cases will be droped from + * the code sooner or later. + */ +#pragma message \ + "Symbian is no longer maintained. CivetWeb will drop Symbian support." #define NO_SSL /* SSL is not supported */ #define NO_CGI /* CGI is not supported */ #define PATH_MAX FILENAME_MAX #endif /* __SYMBIAN32__ */ +#ifndef CIVETWEB_HEADER_INCLUDED /* Include the header file here, so the CivetWeb interface is defined for the * entire implementation, including the following forward definitions. */ #include "civetweb.h" +#endif #ifndef IGNORE_UNUSED_RESULT #define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1)) #endif + +#if defined(__GNUC__) || defined(__MINGW32__) + +/* GCC unused function attribute seems fundamentally broken. + * Several attempts to tell the compiler "THIS FUNCTION MAY BE USED + * OR UNUSED" for individual functions failed. + * Either the compiler creates an "unused-function" warning if a + * function is not marked with __attribute__((unused)). + * On the other hand, if the function is marked with this attribute, + * but is used, the compiler raises a completely idiotic + * "used-but-marked-unused" warning - and + * #pragma GCC diagnostic ignored "-Wused-but-marked-unused" + * raises error: unknown option after ‘#pragma GCC diagnostic’. + * Disable this warning completely, until the GCC guys sober up + * again. + */ + +#pragma GCC diagnostic ignored "-Wunused-function" + +#define FUNCTION_MAY_BE_UNUSED /* __attribute__((unused)) */ + +#else +#define FUNCTION_MAY_BE_UNUSED +#endif + + #ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */ #include #include @@ -127,23 +172,52 @@ mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check"); #include #endif /* !_WIN32_WCE */ -#ifdef __MACH__ + +#ifdef __clang__ +/* When using -Weverything, clang does not accept it's own headers + * in a release build configuration. Disable what is too much in + * -Weverything. */ +#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +#endif + +#if defined(__GNUC__) || defined(__MINGW32__) +/* Who on earth came to the conclusion, using __DATE__ should rise + * an "expansion of date or time macro is not reproducible" + * warning. That's exactly what was intended by using this macro. + * Just disable this nonsense warning. */ + +/* And disabling them does not work either: + * #pragma clang diagnostic ignored "-Wno-error=date-time" + * #pragma clang diagnostic ignored "-Wdate-time" + * So we just have to disable ALL warnings for some lines + * of code. + */ +#endif + + +#ifdef __MACH__ /* Apple OSX section */ + +#ifdef __clang__ +#if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8)) +/* Avoid warnings for Xcode 7. It seems it does no longer exist in Xcode 8 */ +#pragma clang diagnostic ignored "-Wno-reserved-id-macro" +#pragma clang diagnostic ignored "-Wno-keyword-macro" +#endif +#endif #define CLOCK_MONOTONIC (1) #define CLOCK_REALTIME (2) +#include #include #include #include #include #include - -/* clock_gettime is not implemented on OSX */ -int clock_gettime(int clk_id, struct timespec *t); - -int -clock_gettime(int clk_id, struct timespec *t) +/* clock_gettime is not implemented on OSX prior to 10.12 */ +static int +_civet_clock_gettime(int clk_id, struct timespec *t) { memset(t, 0, sizeof(*t)); if (clk_id == CLOCK_REALTIME) { @@ -183,6 +257,25 @@ clock_gettime(int clk_id, struct timespec *t) } return -1; /* EINVAL - Clock ID is unknown */ } + +/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */ +#ifdef __CLOCK_AVAILABILITY +/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be + * declared but it may be NULL at runtime. So we need to check before using + * it. */ +static int +_civet_safe_clock_gettime(int clk_id, struct timespec *t) +{ + if (clock_gettime) { + return clock_gettime(clk_id, t); + } + return _civet_clock_gettime(clk_id, t); +} +#define clock_gettime _civet_safe_clock_gettime +#else +#define clock_gettime _civet_clock_gettime +#endif + #endif @@ -195,18 +288,31 @@ clock_gettime(int clk_id, struct timespec *t) #include #include #include +#include + +#ifndef INT64_MAX +#define INT64_MAX (9223372036854775807) +#endif #ifndef MAX_WORKER_THREADS #define MAX_WORKER_THREADS (1024 * 64) #endif -#ifndef SOCKET_TIMEOUT_QUANTUM -#define SOCKET_TIMEOUT_QUANTUM (10000) + +#ifndef SOCKET_TIMEOUT_QUANTUM /* in ms */ +#define SOCKET_TIMEOUT_QUANTUM (2000) #endif +#define SHUTDOWN_RD (0) +#define SHUTDOWN_WR (1) +#define SHUTDOWN_BOTH (2) + mg_static_assert(MAX_WORKER_THREADS >= 1, "worker threads must be a positive number"); +mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, + "size_t data type size check"); + #if defined(_WIN32) \ && !defined(__SYMBIAN32__) /* WINDOWS / UNIX include block */ #include @@ -235,8 +341,9 @@ mg_static_assert(PATH_MAX >= 1, "path length must be a positive number"); #include #include #include -#else /* _WIN32_WCE */ -#define NO_CGI /* WinCE has no pipes */ +#else /* _WIN32_WCE */ +#define NO_CGI /* WinCE has no pipes */ +#define NO_POPEN /* WinCE has no popen */ typedef long off_t; @@ -291,9 +398,6 @@ typedef long off_t; #define UINT64_FMT "I64u" #define WINCDECL __cdecl -#define SHUT_RD (0) -#define SHUT_WR (1) -#define SHUT_BOTH (2) #define vsnprintf_impl _vsnprintf #define access _access #define mg_sleep(x) (Sleep(x)) @@ -308,7 +412,7 @@ typedef long off_t; #define close(x) (_close(x)) #define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y))) #define RTLD_LAZY (0) -#define fseeko(x, y, z) (_lseeki64(_fileno(x), (y), (z)) == -1 ? -1 : 0) +#define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0) #define fdopen(x, y) (_fdopen((x), (y))) #define write(x, y, z) (_write((x), (y), (unsigned)z)) #define read(x, y, z) (_read((x), (y), (unsigned)z)) @@ -327,8 +431,7 @@ typedef DWORD pthread_key_t; typedef HANDLE pthread_t; typedef struct { CRITICAL_SECTION threadIdSec; - int waitingthreadcount; /* The number of threads queued. */ - pthread_t *waitingthreadhdls; /* The thread handles. */ + struct mg_workerTLS *waiting_thread; /* The chain of threads */ } pthread_cond_t; #ifndef __clockid_t_defined @@ -340,6 +443,13 @@ typedef DWORD clockid_t; #ifndef CLOCK_REALTIME #define CLOCK_REALTIME (2) #endif +#ifndef CLOCK_THREAD +#define CLOCK_THREAD (3) +#endif +#ifndef CLOCK_PROCESS +#define CLOCK_PROCESS (4) +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 1900) #define _TIMESPEC_DEFINED @@ -351,6 +461,106 @@ struct timespec { }; #endif +#if !defined(WIN_PTHREADS_TIME_H) +#define MUST_IMPLEMENT_CLOCK_GETTIME +#endif + +#ifdef MUST_IMPLEMENT_CLOCK_GETTIME +#define clock_gettime mg_clock_gettime +static int +clock_gettime(clockid_t clk_id, struct timespec *tp) +{ + FILETIME ft; + ULARGE_INTEGER li, li2; + BOOL ok = FALSE; + double d; + static double perfcnt_per_sec = 0.0; + + if (tp) { + memset(tp, 0, sizeof(*tp)); + + if (clk_id == CLOCK_REALTIME) { + + /* BEGIN: CLOCK_REALTIME = wall clock (date and time) */ + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */ + tp->tv_sec = (time_t)(li.QuadPart / 10000000); + tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; + ok = TRUE; + /* END: CLOCK_REALTIME */ + + } else if (clk_id == CLOCK_MONOTONIC) { + + /* BEGIN: CLOCK_MONOTONIC = stopwatch (time differences) */ + if (perfcnt_per_sec == 0.0) { + QueryPerformanceFrequency((LARGE_INTEGER *)&li); + perfcnt_per_sec = 1.0 / li.QuadPart; + } + if (perfcnt_per_sec != 0.0) { + QueryPerformanceCounter((LARGE_INTEGER *)&li); + d = li.QuadPart * perfcnt_per_sec; + tp->tv_sec = (time_t)d; + d -= tp->tv_sec; + tp->tv_nsec = (long)(d * 1.0E9); + ok = TRUE; + } + /* END: CLOCK_MONOTONIC */ + + } else if (clk_id == CLOCK_THREAD) { + + /* BEGIN: CLOCK_THREAD = CPU usage of thread */ + FILETIME t_create, t_exit, t_kernel, t_user; + if (GetThreadTimes(GetCurrentThread(), + &t_create, + &t_exit, + &t_kernel, + &t_user)) { + li.LowPart = t_user.dwLowDateTime; + li.HighPart = t_user.dwHighDateTime; + li2.LowPart = t_kernel.dwLowDateTime; + li2.HighPart = t_kernel.dwHighDateTime; + li.QuadPart += li2.QuadPart; + tp->tv_sec = (time_t)(li.QuadPart / 10000000); + tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; + ok = TRUE; + } + /* END: CLOCK_THREAD */ + + } else if (clk_id == CLOCK_PROCESS) { + + /* BEGIN: CLOCK_PROCESS = CPU usage of process */ + FILETIME t_create, t_exit, t_kernel, t_user; + if (GetProcessTimes(GetCurrentProcess(), + &t_create, + &t_exit, + &t_kernel, + &t_user)) { + li.LowPart = t_user.dwLowDateTime; + li.HighPart = t_user.dwHighDateTime; + li2.LowPart = t_kernel.dwLowDateTime; + li2.HighPart = t_kernel.dwHighDateTime; + li.QuadPart += li2.QuadPart; + tp->tv_sec = (time_t)(li.QuadPart / 10000000); + tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; + ok = TRUE; + } + /* END: CLOCK_PROCESS */ + + } else { + + /* BEGIN: unknown clock */ + /* ok = FALSE; already set by init */ + /* END: unknown clock */ + } + } + + return ok ? 0 : -1; +} +#endif + + #define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */ static int pthread_mutex_lock(pthread_mutex_t *); @@ -359,22 +569,17 @@ static void path_to_unicode(const struct mg_connection *conn, const char *path, wchar_t *wbuf, size_t wbuf_len); -struct file; + +/* All file operations need to be rewritten to solve #246. */ + +#include "file_ops.inl" + +struct mg_file; + static const char * -mg_fgets(char *buf, size_t size, struct file *filep, char **p); +mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p); -#if defined(HAVE_STDINT) -#include -#else -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned __int64 uint64_t; -typedef __int64 int64_t; -#define INT64_MAX (9223372036854775807) -#endif /* HAVE_STDINT */ - /* POSIX dirent interface */ struct dirent { char d_name[PATH_MAX]; @@ -402,8 +607,8 @@ struct pollfd { #pragma comment(lib, "Ws2_32.lib") #endif -#else /* defined(_WIN32) && !defined(__SYMBIAN32__) - WINDOWS / UNIX include \ - block */ +#else /* defined(_WIN32) && !defined(__SYMBIAN32__) - \ + WINDOWS / UNIX include block */ #include #include @@ -477,8 +682,8 @@ typedef int SOCKET; #define socklen_t int #endif /* hpux */ -#endif /* defined(_WIN32) && !defined(__SYMBIAN32__) - WINDOWS / UNIX include \ - block */ +#endif /* defined(_WIN32) && !defined(__SYMBIAN32__) - \ + WINDOWS / UNIX include block */ /* va_copy should always be a macro, C99 and C++11 - DTL */ #ifndef va_copy @@ -496,6 +701,8 @@ typedef int SOCKET; static CRITICAL_SECTION global_log_file_lock; + +FUNCTION_MAY_BE_UNUSED static DWORD pthread_self(void) { @@ -503,6 +710,7 @@ pthread_self(void) } +FUNCTION_MAY_BE_UNUSED static int pthread_key_create( pthread_key_t *key, @@ -519,6 +727,7 @@ pthread_key_create( } +FUNCTION_MAY_BE_UNUSED static int pthread_key_delete(pthread_key_t key) { @@ -526,6 +735,7 @@ pthread_key_delete(pthread_key_t key) } +FUNCTION_MAY_BE_UNUSED static int pthread_setspecific(pthread_key_t key, void *value) { @@ -533,6 +743,7 @@ pthread_setspecific(pthread_key_t key, void *value) } +FUNCTION_MAY_BE_UNUSED static void * pthread_getspecific(pthread_key_t key) { @@ -555,83 +766,361 @@ static pthread_mutexattr_t pthread_mutex_attr; #define MAX_CGI_ENVIR_VARS (256) #define MG_BUF_LEN (8192) -#ifndef MAX_REQUEST_SIZE -#define MAX_REQUEST_SIZE (16384) -#endif - -mg_static_assert(MAX_REQUEST_SIZE >= 256, - "request size length must be a positive number"); - #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) -#if !defined(DEBUG_TRACE) -#if defined(DEBUG) + +#if defined(_WIN32_WCE) +/* Create substitutes for POSIX functions in Win32. */ + +#if defined(__MINGW32__) +/* Show no warning in case system functions are not used. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif -static void DEBUG_TRACE_FUNC(const char *func, - unsigned line, - PRINTF_FORMAT_STRING(const char *fmt), - ...) PRINTF_ARGS(3, 4); - -static void -DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...) +FUNCTION_MAY_BE_UNUSED +static time_t +time(time_t *ptime) { - va_list args; - flockfile(stdout); - printf("*** %lu.%p.%s.%u: ", - (unsigned long)time(NULL), - (void *)pthread_self(), - func, - line); - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - putchar('\n'); - fflush(stdout); - funlockfile(stdout); + time_t t; + SYSTEMTIME st; + FILETIME ft; + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime); + + if (ptime != NULL) { + *ptime = t; + } + + return t; } -#define DEBUG_TRACE(fmt, ...) \ - DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__) +FUNCTION_MAY_BE_UNUSED +static struct tm * +localtime_s(const time_t *ptime, struct tm *ptm) +{ + int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF; + FILETIME ft, lft; + SYSTEMTIME st; + TIME_ZONE_INFORMATION tzinfo; + + if (ptm == NULL) { + return NULL; + } + + *(int64_t *)&ft = t; + FileTimeToLocalFileTime(&ft, &lft); + FileTimeToSystemTime(&lft, &st); + ptm->tm_year = st.wYear - 1900; + ptm->tm_mon = st.wMonth - 1; + ptm->tm_wday = st.wDayOfWeek; + ptm->tm_mday = st.wDay; + ptm->tm_hour = st.wHour; + ptm->tm_min = st.wMinute; + ptm->tm_sec = st.wSecond; + ptm->tm_yday = 0; /* hope nobody uses this */ + ptm->tm_isdst = + (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT) ? 1 : 0; + + return ptm; +} + + +FUNCTION_MAY_BE_UNUSED +static struct tm * +gmtime_s(const time_t *ptime, struct tm *ptm) +{ + /* FIXME(lsm): fix this. */ + return localtime_s(ptime, ptm); +} + + +static int mg_atomic_inc(volatile int *addr); +static struct tm tm_array[MAX_WORKER_THREADS]; +static int tm_index = 0; + + +FUNCTION_MAY_BE_UNUSED +static struct tm * +localtime(const time_t *ptime) +{ + int i = mg_atomic_inc(&tm_index) % (sizeof(tm_array) / sizeof(tm_array[0])); + return localtime_s(ptime, tm_array + i); +} + + +FUNCTION_MAY_BE_UNUSED +static struct tm * +gmtime(const time_t *ptime) +{ + int i = mg_atomic_inc(&tm_index) % ARRAY_SIZE(tm_array); + return gmtime_s(ptime, tm_array + i); +} + + +FUNCTION_MAY_BE_UNUSED +static size_t +strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm) +{ + /* TODO: (void)mg_snprintf(NULL, dst, dst_size, "implement strftime() + * for WinCE"); */ + return 0; +} + +#define _beginthreadex(psec, stack, func, prm, flags, ptid) \ + (uintptr_t) CreateThread(psec, stack, func, prm, flags, ptid) + +#define remove(f) mg_remove(NULL, f) + + +FUNCTION_MAY_BE_UNUSED +static int +rename(const char *a, const char *b) +{ + wchar_t wa[PATH_MAX]; + wchar_t wb[PATH_MAX]; + path_to_unicode(NULL, a, wa, ARRAY_SIZE(wa)); + path_to_unicode(NULL, b, wb, ARRAY_SIZE(wb)); + + return MoveFileW(wa, wb) ? 0 : -1; +} + + +struct stat { + int64_t st_size; + time_t st_mtime; +}; + + +FUNCTION_MAY_BE_UNUSED +static int +stat(const char *name, struct stat *st) +{ + wchar_t wbuf[PATH_MAX]; + WIN32_FILE_ATTRIBUTE_DATA attr; + time_t creation_time, write_time; + + path_to_unicode(NULL, name, wbuf, ARRAY_SIZE(wbuf)); + memset(&attr, 0, sizeof(attr)); + + GetFileAttributesExW(wbuf, GetFileExInfoStandard, &attr); + st->st_size = + (((int64_t)attr.nFileSizeHigh) << 32) + (int64_t)attr.nFileSizeLow; + + write_time = SYS2UNIX_TIME(attr.ftLastWriteTime.dwLowDateTime, + attr.ftLastWriteTime.dwHighDateTime); + creation_time = SYS2UNIX_TIME(attr.ftCreationTime.dwLowDateTime, + attr.ftCreationTime.dwHighDateTime); + + if (creation_time > write_time) { + st->st_mtime = creation_time; + } else { + st->st_mtime = write_time; + } + return 0; +} + +#define access(x, a) 1 /* not required anyway */ + +/* WinCE-TODO: define stat, remove, rename, _rmdir, _lseeki64 */ +/* Values from errno.h in Windows SDK (Visual Studio). */ +#define EEXIST 17 +#define EACCES 13 +#define ENOENT 2 + +#if defined(__MINGW32__) +/* Enable unused function warning again */ +#pragma GCC diagnostic pop +#endif + +#endif /* defined(_WIN32_WCE) */ + + +#if defined(__GNUC__) || defined(__MINGW32__) +/* Show no warning in case system functions are not used. */ +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) || defined(__MINGW32__) */ +#if defined(__clang__) +/* Show no warning in case system functions are not used. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +static pthread_mutex_t global_lock_mutex; + + +#if defined(_WIN32) && !defined(__SYMBIAN32__) +/* Forward declaration for Windows */ +FUNCTION_MAY_BE_UNUSED +static int pthread_mutex_lock(pthread_mutex_t *mutex); + +FUNCTION_MAY_BE_UNUSED +static int pthread_mutex_unlock(pthread_mutex_t *mutex); +#endif + + +FUNCTION_MAY_BE_UNUSED +static void +mg_global_lock(void) +{ + (void)pthread_mutex_lock(&global_lock_mutex); +} + + +FUNCTION_MAY_BE_UNUSED +static void +mg_global_unlock(void) +{ + (void)pthread_mutex_unlock(&global_lock_mutex); +} + + +FUNCTION_MAY_BE_UNUSED +static int +mg_atomic_inc(volatile int *addr) +{ + int ret; +#if defined(_WIN32) && !defined(__SYMBIAN32__) && !defined(NO_ATOMICS) + /* Depending on the SDK, this function uses either + * (volatile unsigned int *) or (volatile LONG *), + * so whatever you use, the other SDK is likely to raise a warning. */ + ret = InterlockedIncrement((volatile long *)addr); +#elif defined(__GNUC__) \ + && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \ + && !defined(NO_ATOMICS) + ret = __sync_add_and_fetch(addr, 1); #else -#define DEBUG_TRACE(fmt, ...) \ - do { \ - } while (0) -#endif /* DEBUG */ -#endif /* DEBUG_TRACE */ + mg_global_lock(); + ret = (++(*addr)); + mg_global_unlock(); +#endif + return ret; +} -#if defined(MEMORY_DEBUGGING) -unsigned long mg_memory_debug_blockCount = 0; -unsigned long mg_memory_debug_totalMemUsed = 0; + +FUNCTION_MAY_BE_UNUSED +static int +mg_atomic_dec(volatile int *addr) +{ + int ret; +#if defined(_WIN32) && !defined(__SYMBIAN32__) && !defined(NO_ATOMICS) + /* Depending on the SDK, this function uses either + * (volatile unsigned int *) or (volatile LONG *), + * so whatever you use, the other SDK is likely to raise a warning. */ + ret = InterlockedDecrement((volatile long *)addr); +#elif defined(__GNUC__) \ + && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \ + && !defined(NO_ATOMICS) + ret = __sync_sub_and_fetch(addr, 1); +#else + mg_global_lock(); + ret = (--(*addr)); + mg_global_unlock(); +#endif + return ret; +} + + +#if defined(USE_SERVER_STATS) +static int64_t +mg_atomic_add(volatile int64_t *addr, int64_t value) +{ + int64_t ret; +#if defined(_WIN64) && !defined(__SYMBIAN32__) && !defined(NO_ATOMICS) + ret = InterlockedAdd64(addr, value); +#elif defined(__GNUC__) \ + && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \ + && !defined(NO_ATOMICS) + ret = __sync_add_and_fetch(addr, value); +#else + mg_global_lock(); + *addr += value; + ret = (*addr); + mg_global_unlock(); +#endif + return ret; +} +#endif + + +#if defined(__GNUC__) +/* Show no warning in case system functions are not used. */ +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic pop +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) */ +#if defined(__clang__) +/* Show no warning in case system functions are not used. */ +#pragma clang diagnostic pop +#endif + + +#if defined(USE_SERVER_STATS) + +struct mg_memory_stat { + volatile int64_t totalMemUsed; + volatile int64_t maxMemUsed; + volatile int blockCount; +}; + + +static struct mg_memory_stat *get_memory_stat(struct mg_context *ctx); static void * -mg_malloc_ex(size_t size, const char *file, unsigned line) +mg_malloc_ex(size_t size, + struct mg_context *ctx, + const char *file, + unsigned line) { - void *data = malloc(size + sizeof(size_t)); + void *data = malloc(size + 2 * sizeof(uintptr_t)); void *memory = 0; + struct mg_memory_stat *mstat = get_memory_stat(ctx); + +#if defined(MEMORY_DEBUGGING) char mallocStr[256]; +#else + (void)file; + (void)line; +#endif if (data) { - *(size_t *)data = size; - mg_memory_debug_totalMemUsed += size; - mg_memory_debug_blockCount++; - memory = (void *)(((char *)data) + sizeof(size_t)); + int64_t mmem = mg_atomic_add(&mstat->totalMemUsed, (int64_t)size); + if (mmem > mstat->maxMemUsed) { + /* could use atomic compare exchange, but this + * seems overkill for statistics data */ + mstat->maxMemUsed = mmem; + } + + mg_atomic_inc(&mstat->blockCount); + ((uintptr_t *)data)[0] = size; + ((uintptr_t *)data)[1] = (uintptr_t)mstat; + memory = (void *)(((char *)data) + 2 * sizeof(uintptr_t)); } +#if defined(MEMORY_DEBUGGING) sprintf(mallocStr, "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n", memory, (unsigned long)size, - mg_memory_debug_totalMemUsed, - mg_memory_debug_blockCount, + (unsigned long)mstat->totalMemUsed, + (unsigned long)mstat->blockCount, file, line); #if defined(_WIN32) OutputDebugStringA(mallocStr); #else DEBUG_TRACE("%s", mallocStr); +#endif #endif return memory; @@ -639,11 +1128,16 @@ mg_malloc_ex(size_t size, const char *file, unsigned line) static void * -mg_calloc_ex(size_t count, size_t size, const char *file, unsigned line) +mg_calloc_ex(size_t count, + size_t size, + struct mg_context *ctx, + const char *file, + unsigned line) { - void *data = mg_malloc_ex(size * count, file, line); + void *data = mg_malloc_ex(size * count, ctx, file, line); + if (data) { - memset(data, 0, size); + memset(data, 0, size * count); } return data; } @@ -652,20 +1146,29 @@ mg_calloc_ex(size_t count, size_t size, const char *file, unsigned line) static void mg_free_ex(void *memory, const char *file, unsigned line) { + void *data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t)); + + +#if defined(MEMORY_DEBUGGING) char mallocStr[256]; - void *data = (void *)(((char *)memory) - sizeof(size_t)); - size_t size; +#else + (void)file; + (void)line; +#endif if (memory) { - size = *(size_t *)data; - mg_memory_debug_totalMemUsed -= size; - mg_memory_debug_blockCount--; + uintptr_t size = ((uintptr_t *)data)[0]; + struct mg_memory_stat *mstat = + (struct mg_memory_stat *)(((uintptr_t *)data)[1]); + mg_atomic_add(&mstat->totalMemUsed, -(int64_t)size); + mg_atomic_dec(&mstat->blockCount); +#if defined(MEMORY_DEBUGGING) sprintf(mallocStr, "MEM: %p %5lu free %7lu %4lu --- %s:%u\n", memory, (unsigned long)size, - mg_memory_debug_totalMemUsed, - mg_memory_debug_blockCount, + (unsigned long)mstat->totalMemUsed, + (unsigned long)mstat->blockCount, file, line); #if defined(_WIN32) @@ -673,34 +1176,48 @@ mg_free_ex(void *memory, const char *file, unsigned line) #else DEBUG_TRACE("%s", mallocStr); #endif - +#endif free(data); } } static void * -mg_realloc_ex(void *memory, size_t newsize, const char *file, unsigned line) +mg_realloc_ex(void *memory, + size_t newsize, + struct mg_context *ctx, + const char *file, + unsigned line) { - char mallocStr[256]; void *data; void *_realloc; - size_t oldsize; + uintptr_t oldsize; + +#if defined(MEMORY_DEBUGGING) + char mallocStr[256]; +#else + (void)file; + (void)line; +#endif if (newsize) { if (memory) { - data = (void *)(((char *)memory) - sizeof(size_t)); - oldsize = *(size_t *)data; - _realloc = realloc(data, newsize + sizeof(size_t)); + /* Reallocate existing block */ + struct mg_memory_stat *mstat; + data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t)); + oldsize = ((uintptr_t *)data)[0]; + mstat = (struct mg_memory_stat *)((uintptr_t *)data)[1]; + _realloc = realloc(data, newsize + 2 * sizeof(uintptr_t)); if (_realloc) { data = _realloc; - mg_memory_debug_totalMemUsed -= oldsize; + mg_atomic_add(&mstat->totalMemUsed, -(int64_t)oldsize); +#if defined(MEMORY_DEBUGGING) sprintf(mallocStr, "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n", memory, (unsigned long)oldsize, - mg_memory_debug_totalMemUsed, - mg_memory_debug_blockCount, + (unsigned long)mstat->totalMemUsed, + (unsigned long)mstat->blockCount, file, line); #if defined(_WIN32) @@ -708,13 +1225,15 @@ mg_realloc_ex(void *memory, size_t newsize, const char *file, unsigned line) #else DEBUG_TRACE("%s", mallocStr); #endif - mg_memory_debug_totalMemUsed += newsize; +#endif + mg_atomic_add(&mstat->totalMemUsed, (int64_t)newsize); +#if defined(MEMORY_DEBUGGING) sprintf(mallocStr, "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n", memory, (unsigned long)newsize, - mg_memory_debug_totalMemUsed, - mg_memory_debug_blockCount, + (unsigned long)mstat->totalMemUsed, + (unsigned long)mstat->blockCount, file, line); #if defined(_WIN32) @@ -722,20 +1241,25 @@ mg_realloc_ex(void *memory, size_t newsize, const char *file, unsigned line) #else DEBUG_TRACE("%s", mallocStr); #endif - *(size_t *)data = newsize; - data = (void *)(((char *)data) + sizeof(size_t)); +#endif + *(uintptr_t *)data = newsize; + data = (void *)(((char *)data) + 2 * sizeof(uintptr_t)); } else { +#if defined(MEMORY_DEBUGGING) #if defined(_WIN32) OutputDebugStringA("MEM: realloc failed\n"); #else DEBUG_TRACE("%s", "MEM: realloc failed\n"); +#endif #endif return _realloc; } } else { - data = mg_malloc_ex(newsize, file, line); + /* Allocate new block */ + data = mg_malloc_ex(newsize, ctx, file, line); } } else { + /* Free existing block */ data = 0; mg_free_ex(memory, file, line); } @@ -743,12 +1267,16 @@ mg_realloc_ex(void *memory, size_t newsize, const char *file, unsigned line) return data; } -#define mg_malloc(a) mg_malloc_ex(a, __FILE__, __LINE__) -#define mg_calloc(a, b) mg_calloc_ex(a, b, __FILE__, __LINE__) -#define mg_realloc(a, b) mg_realloc_ex(a, b, __FILE__, __LINE__) +#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__) +#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__) +#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__) #define mg_free(a) mg_free_ex(a, __FILE__, __LINE__) -#else +#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__) +#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__) +#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__) + +#else /* USE_SERVER_STATS */ static __inline void * mg_malloc(size_t a) @@ -774,7 +1302,12 @@ mg_free(void *a) free(a); } -#endif +#define mg_malloc_ctx(a, c) mg_malloc(a) +#define mg_calloc_ctx(a, b, c) mg_calloc(a, b) +#define mg_realloc_ctx(a, b, c) mg_realloc(a, b) +#define mg_free_ctx(a, c) mg_free(a) + +#endif /* USE_SERVER_STATS */ static void mg_vsnprintf(const struct mg_connection *conn, @@ -816,11 +1349,183 @@ static void mg_snprintf(const struct mg_connection *conn, #define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc #define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free #define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf -#ifdef _WIN32 /* vsnprintf must not be used in any system, * \ +#ifdef _WIN32 /* vsnprintf must not be used in any system, * \ \ \ \ * but this define only works well for Windows. */ #define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf #endif + +/* mg_init_library counter */ +static int mg_init_library_called = 0; + +#if !defined(NO_SSL) +static int mg_ssl_initialized = 0; +#endif + +static pthread_key_t sTlsKey; /* Thread local storage index */ +static int thread_idx_max = 0; + + +struct mg_workerTLS { + int is_master; + unsigned long thread_idx; +#if defined(_WIN32) && !defined(__SYMBIAN32__) + HANDLE pthread_cond_helper_mutex; + struct mg_workerTLS *next_waiting_thread; +#endif +}; + + +#if defined(__GNUC__) || defined(__MINGW32__) +/* Show no warning in case system functions are not used. */ +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) || defined(__MINGW32__) */ +#if defined(__clang__) +/* Show no warning in case system functions are not used. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + + +/* Get a unique thread ID as unsigned long, independent from the data type + * of thread IDs defined by the operating system API. + * If two calls to mg_current_thread_id return the same value, they calls + * are done from the same thread. If they return different values, they are + * done from different threads. (Provided this function is used in the same + * process context and threads are not repeatedly created and deleted, but + * CivetWeb does not do that). + * This function must match the signature required for SSL id callbacks: + * CRYPTO_set_id_callback + */ +FUNCTION_MAY_BE_UNUSED +static unsigned long +mg_current_thread_id(void) +{ +#ifdef _WIN32 + return GetCurrentThreadId(); +#else + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +/* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)" + * or not, so one of the two conditions will be unreachable by construction. + * Unfortunately the C standard does not define a way to check this at + * compile time, since the #if preprocessor conditions can not use the sizeof + * operator as an argument. */ +#endif + + if (sizeof(pthread_t) > sizeof(unsigned long)) { + /* This is the problematic case for CRYPTO_set_id_callback: + * The OS pthread_t can not be cast to unsigned long. */ + struct mg_workerTLS *tls = + (struct mg_workerTLS *)pthread_getspecific(sTlsKey); + if (tls == NULL) { + /* SSL called from an unknown thread: Create some thread index. + */ + tls = (struct mg_workerTLS *)mg_malloc(sizeof(struct mg_workerTLS)); + tls->is_master = -2; /* -2 means "3rd party thread" */ + tls->thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max); + pthread_setspecific(sTlsKey, tls); + } + return tls->thread_idx; + } else { + /* pthread_t may be any data type, so a simple cast to unsigned long + * can rise a warning/error, depending on the platform. + * Here memcpy is used as an anything-to-anything cast. */ + unsigned long ret = 0; + pthread_t t = pthread_self(); + memcpy(&ret, &t, sizeof(pthread_t)); + return ret; + } + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif +} + + +FUNCTION_MAY_BE_UNUSED +static uint64_t +mg_get_current_time_ns(void) +{ + struct timespec tsnow; + clock_gettime(CLOCK_REALTIME, &tsnow); + return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec; +} + + +#if defined(__GNUC__) +/* Show no warning in case system functions are not used. */ +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic pop +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) */ +#if defined(__clang__) +/* Show no warning in case system functions are not used. */ +#pragma clang diagnostic pop +#endif + + +#if !defined(DEBUG_TRACE) +#if defined(DEBUG) +static void DEBUG_TRACE_FUNC(const char *func, + unsigned line, + PRINTF_FORMAT_STRING(const char *fmt), + ...) PRINTF_ARGS(3, 4); + +static void +DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...) +{ + va_list args; + uint64_t nsnow; + static uint64_t nslast; + struct timespec tsnow; + + /* Get some operating system independent thread id */ + unsigned long thread_id = mg_current_thread_id(); + + clock_gettime(CLOCK_REALTIME, &tsnow); + nsnow = ((uint64_t)tsnow.tv_sec) * ((uint64_t)1000000000) + + ((uint64_t)tsnow.tv_nsec); + + if (!nslast) { + nslast = nsnow; + } + + flockfile(stdout); + printf("*** %lu.%09lu %12" INT64_FMT " %lu %s:%u: ", + (unsigned long)tsnow.tv_sec, + (unsigned long)tsnow.tv_nsec, + nsnow - nslast, + thread_id, + func, + line); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + putchar('\n'); + fflush(stdout); + funlockfile(stdout); + nslast = nsnow; +} + +#define DEBUG_TRACE(fmt, ...) \ + DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__) + +#else +#define DEBUG_TRACE(fmt, ...) \ + do { \ + } while (0) +#endif /* DEBUG */ +#endif /* DEBUG_TRACE */ + + #define MD5_STATIC static #include "md5.inl" @@ -845,13 +1550,24 @@ typedef int socklen_t; #define MGSQLEN (20) #endif + +#if defined(NO_SSL) +typedef struct SSL SSL; /* dummy for SSL argument to push/pull */ +typedef struct SSL_CTX SSL_CTX; +#else #if defined(NO_SSL_DL) #include #include #include #include #include +#include +#include +#include +#include +#include #else + /* SSL loaded dynamically from DLL. * I put the prototypes here to be independent from OpenSSL source * installation. */ @@ -860,11 +1576,22 @@ typedef struct ssl_st SSL; typedef struct ssl_method_st SSL_METHOD; typedef struct ssl_ctx_st SSL_CTX; typedef struct x509_store_ctx_st X509_STORE_CTX; +typedef struct x509_name X509_NAME; +typedef struct asn1_integer ASN1_INTEGER; +typedef struct bignum BIGNUM; +typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS; +typedef struct evp_md EVP_MD; +typedef struct x509 X509; + #define SSL_CTRL_OPTIONS (32) #define SSL_CTRL_CLEAR_OPTIONS (77) #define SSL_CTRL_SET_ECDH_AUTO (94) +#define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L +#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L +#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L + #define SSL_VERIFY_NONE (0) #define SSL_VERIFY_PEER (1) #define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2) @@ -876,12 +1603,184 @@ typedef struct x509_store_ctx_st X509_STORE_CTX; #define SSL_OP_NO_TLSv1_2 (0x08000000L) #define SSL_OP_NO_TLSv1_1 (0x10000000L) #define SSL_OP_SINGLE_DH_USE (0x00100000L) +#define SSL_OP_CIPHER_SERVER_PREFERENCE (0x00400000L) +#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (0x00010000L) +#define SSL_OP_NO_COMPRESSION (0x00020000L) + +#define SSL_CB_HANDSHAKE_START (0x10) +#define SSL_CB_HANDSHAKE_DONE (0x20) + +#define SSL_ERROR_NONE (0) +#define SSL_ERROR_SSL (1) +#define SSL_ERROR_WANT_READ (2) +#define SSL_ERROR_WANT_WRITE (3) +#define SSL_ERROR_WANT_X509_LOOKUP (4) +#define SSL_ERROR_SYSCALL (5) /* see errno */ +#define SSL_ERROR_ZERO_RETURN (6) +#define SSL_ERROR_WANT_CONNECT (7) +#define SSL_ERROR_WANT_ACCEPT (8) + struct ssl_func { const char *name; /* SSL function name */ void (*ptr)(void); /* Function pointer */ }; + +#ifdef OPENSSL_API_1_1 + +#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr) +#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr) +#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr) +#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr) +#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr) +#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr) +#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr) +#define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr) +#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr) +#define TLS_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr) +#define OPENSSL_init_ssl \ + (*(int (*)(uint64_t opts, \ + const OPENSSL_INIT_SETTINGS *settings))ssl_sw[10].ptr) +#define SSL_CTX_use_PrivateKey_file \ + (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr) +#define SSL_CTX_use_certificate_file \ + (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr) +#define SSL_CTX_set_default_passwd_cb \ + (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr) +#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) +#define SSL_CTX_use_certificate_chain_file \ + (*(int (*)(SSL_CTX *, const char *))ssl_sw[15].ptr) +#define TLS_client_method (*(SSL_METHOD * (*)(void))ssl_sw[16].ptr) +#define SSL_pending (*(int (*)(SSL *))ssl_sw[17].ptr) +#define SSL_CTX_set_verify \ + (*(void (*)(SSL_CTX *, \ + int, \ + int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18].ptr) +#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[19].ptr) +#define SSL_CTX_load_verify_locations \ + (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[20].ptr) +#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[21].ptr) +#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[22].ptr) +#define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[23].ptr) +#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[24].ptr) +#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[25].ptr) +#define SSL_CIPHER_get_name \ + (*(const char *(*)(const SSL_CIPHER *))ssl_sw[26].ptr) +#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[27].ptr) +#define SSL_CTX_set_session_id_context \ + (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[28].ptr) +#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[29].ptr) +#define SSL_CTX_set_cipher_list \ + (*(int (*)(SSL_CTX *, const char *))ssl_sw[30].ptr) +#define SSL_CTX_set_options \ + (*(unsigned long (*)(SSL_CTX *, unsigned long))ssl_sw[31].ptr) +#define SSL_CTX_set_info_callback \ + (*(void (*)(SSL_CTX * ctx, \ + void (*callback)(SSL * s, int, int)))ssl_sw[32].ptr) +#define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr) +#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr) + +#define SSL_CTX_clear_options(ctx, op) \ + SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL) +#define SSL_CTX_set_ecdh_auto(ctx, onoff) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL) + +#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) +#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) + +#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) +#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) + +#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[0].ptr) +#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[1].ptr) +#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[2].ptr) +#define CONF_modules_unload (*(void (*)(int))crypto_sw[3].ptr) +#define X509_free (*(void (*)(X509 *))crypto_sw[4].ptr) +#define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[5].ptr) +#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[6].ptr) +#define X509_NAME_oneline \ + (*(char *(*)(X509_NAME *, char *, int))crypto_sw[7].ptr) +#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[8].ptr) +#define EVP_get_digestbyname \ + (*(const EVP_MD *(*)(const char *))crypto_sw[9].ptr) +#define EVP_Digest \ + (*(int (*)( \ + const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \ + crypto_sw[10].ptr) +#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[11].ptr) +#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[12].ptr) +#define ASN1_INTEGER_to_BN \ + (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[13].ptr) +#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[14].ptr) +#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[15].ptr) + +#define OPENSSL_free(a) CRYPTO_free(a) + + +/* set_ssl_option() function updates this array. + * It loads SSL library dynamically and changes NULLs to the actual addresses + * of respective functions. The macros above (like SSL_connect()) are really + * just calling these functions indirectly via the pointer. */ +static struct ssl_func ssl_sw[] = {{"SSL_free", NULL}, + {"SSL_accept", NULL}, + {"SSL_connect", NULL}, + {"SSL_read", NULL}, + {"SSL_write", NULL}, + {"SSL_get_error", NULL}, + {"SSL_set_fd", NULL}, + {"SSL_new", NULL}, + {"SSL_CTX_new", NULL}, + {"TLS_server_method", NULL}, + {"OPENSSL_init_ssl", NULL}, + {"SSL_CTX_use_PrivateKey_file", NULL}, + {"SSL_CTX_use_certificate_file", NULL}, + {"SSL_CTX_set_default_passwd_cb", NULL}, + {"SSL_CTX_free", NULL}, + {"SSL_CTX_use_certificate_chain_file", NULL}, + {"TLS_client_method", NULL}, + {"SSL_pending", NULL}, + {"SSL_CTX_set_verify", NULL}, + {"SSL_shutdown", NULL}, + {"SSL_CTX_load_verify_locations", NULL}, + {"SSL_CTX_set_default_verify_paths", NULL}, + {"SSL_CTX_set_verify_depth", NULL}, + {"SSL_get_peer_certificate", NULL}, + {"SSL_get_version", NULL}, + {"SSL_get_current_cipher", NULL}, + {"SSL_CIPHER_get_name", NULL}, + {"SSL_CTX_check_private_key", NULL}, + {"SSL_CTX_set_session_id_context", NULL}, + {"SSL_CTX_ctrl", NULL}, + {"SSL_CTX_set_cipher_list", NULL}, + {"SSL_CTX_set_options", NULL}, + {"SSL_CTX_set_info_callback", NULL}, + {"SSL_get_ex_data", NULL}, + {"SSL_set_ex_data", NULL}, + {NULL, NULL}}; + + +/* Similar array as ssl_sw. These functions could be located in different + * lib. */ +static struct ssl_func crypto_sw[] = {{"ERR_get_error", NULL}, + {"ERR_error_string", NULL}, + {"ERR_remove_state", NULL}, + {"CONF_modules_unload", NULL}, + {"X509_free", NULL}, + {"X509_get_subject_name", NULL}, + {"X509_get_issuer_name", NULL}, + {"X509_NAME_oneline", NULL}, + {"X509_get_serialNumber", NULL}, + {"EVP_get_digestbyname", NULL}, + {"EVP_Digest", NULL}, + {"i2d_X509", NULL}, + {"BN_bn2hex", NULL}, + {"ASN1_INTEGER_to_BN", NULL}, + {"BN_free", NULL}, + {"CRYPTO_free", NULL}, + {NULL, NULL}}; +#else + #define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr) #define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr) #define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr) @@ -925,6 +1824,12 @@ struct ssl_func { #define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr) #define SSL_CTX_set_cipher_list \ (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr) +#define SSL_CTX_set_info_callback \ + (*(void (*)(SSL_CTX * ctx, \ + void (*callback)(SSL * s, int, int)))ssl_sw[32].ptr) +#define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr) +#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr) + #define SSL_CTX_set_options(ctx, op) \ SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL) #define SSL_CTX_clear_options(ctx, op) \ @@ -932,6 +1837,13 @@ struct ssl_func { #define SSL_CTX_set_ecdh_auto(ctx, onoff) \ SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL) + +#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) +#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) + +#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) +#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) + #define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr) #define CRYPTO_set_locking_callback \ (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr) @@ -945,7 +1857,28 @@ struct ssl_func { #define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr) #define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr) #define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr) +#define X509_free (*(void (*)(X509 *))crypto_sw[11].ptr) +#define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[12].ptr) +#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[13].ptr) +#define X509_NAME_oneline \ + (*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr) +#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[15].ptr) +#define i2c_ASN1_INTEGER \ + (*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr) +#define EVP_get_digestbyname \ + (*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr) +#define EVP_Digest \ + (*(int (*)( \ + const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \ + crypto_sw[18].ptr) +#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr) +#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[20].ptr) +#define ASN1_INTEGER_to_BN \ + (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[21].ptr) +#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[22].ptr) +#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[23].ptr) +#define OPENSSL_free(a) CRYPTO_free(a) /* set_ssl_option() function updates this array. * It loads SSL library dynamically and changes NULLs to the actual addresses @@ -983,12 +1916,14 @@ static struct ssl_func ssl_sw[] = {{"SSL_free", NULL}, {"SSL_CTX_set_session_id_context", NULL}, {"SSL_CTX_ctrl", NULL}, {"SSL_CTX_set_cipher_list", NULL}, + {"SSL_CTX_set_info_callback", NULL}, + {"SSL_get_ex_data", NULL}, + {"SSL_set_ex_data", NULL}, {NULL, NULL}}; /* Similar array as ssl_sw. These functions could be located in different * lib. */ -#if !defined(NO_SSL) static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL}, {"CRYPTO_set_locking_callback", NULL}, {"CRYPTO_set_id_callback", NULL}, @@ -1000,9 +1935,23 @@ static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL}, {"CONF_modules_unload", NULL}, {"CRYPTO_cleanup_all_ex_data", NULL}, {"EVP_cleanup", NULL}, + {"X509_free", NULL}, + {"X509_get_subject_name", NULL}, + {"X509_get_issuer_name", NULL}, + {"X509_NAME_oneline", NULL}, + {"X509_get_serialNumber", NULL}, + {"i2c_ASN1_INTEGER", NULL}, + {"EVP_get_digestbyname", NULL}, + {"EVP_Digest", NULL}, + {"i2d_X509", NULL}, + {"BN_bn2hex", NULL}, + {"ASN1_INTEGER_to_BN", NULL}, + {"BN_free", NULL}, + {"CRYPTO_free", NULL}, {NULL, NULL}}; -#endif /* NO_SSL */ +#endif /* OPENSSL_API_1_1 */ #endif /* NO_SSL_DL */ +#endif /* NO_SSL */ #if !defined(NO_CACHING) @@ -1020,7 +1969,8 @@ static const char *month_names[] = {"Jan", "Dec"}; #endif /* !NO_CACHING */ -/* Unified socket address. For IPv6 support, add IPv6 address structure in the +/* Unified socket address. For IPv6 support, add IPv6 address structure in + * the * union u. */ union usa { struct sockaddr sa; @@ -1036,19 +1986,45 @@ struct vec { size_t len; }; -struct file { +struct mg_file_stat { + /* File properties filled by mg_stat: */ uint64_t size; time_t last_modified; + int is_directory; /* Set to 1 if mg_stat is called for a directory */ + int is_gzipped; /* Set to 1 if the content is gzipped, in which + * case we need a "Content-Eencoding: gzip" header */ + int location; /* 0 = nowhere, 1 = on disk, 2 = in memory */ +}; + +struct mg_file_in_memory { + char *p; + uint32_t pos; + char mode; +}; + +struct mg_file_access { + /* File properties filled by mg_fopen: */ FILE *fp; - const char *membuf; /* Non-NULL if file data is in memory */ - int is_directory; - int gzipped; /* set to 1 if the content is gzipped - * in which case we need a content-encoding: gzip header */ + /* TODO (low): Replace "membuf" implementation by a "file in memory" + * support library. Use some struct mg_file_in_memory *mf; instead of + * membuf char pointer. */ + const char *membuf; +}; + +struct mg_file { + struct mg_file_stat stat; + struct mg_file_access access; }; #define STRUCT_FILE_INITIALIZER \ { \ - (uint64_t)0, (time_t)0, (FILE *)NULL, (const char *)NULL, 0, 0 \ + { \ + (uint64_t)0, (time_t)0, 0, 0, 0 \ + } \ + , \ + { \ + (FILE *) NULL, (const char *)NULL \ + } \ } /* Describes listening socket, or socket which was accept()-ed by the master @@ -1060,6 +2036,7 @@ struct socket { unsigned char is_ssl; /* Is port SSL-ed */ unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL * port */ + unsigned char in_use; /* Is valid */ }; /* NOTE(lsm): this enum shoulds be in sync with the config_options below. */ @@ -1084,11 +2061,14 @@ enum { LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE, + SSL_CERTIFICATE_CHAIN, NUM_THREADS, RUN_AS_USER, - REWRITE, + URL_REWRITE_PATTERN, HIDE_FILES, REQUEST_TIMEOUT, + KEEP_ALIVE_TIMEOUT, + LINGER_TIMEOUT, SSL_DO_VERIFY_PEER, SSL_CA_PATH, SSL_CA_FILE, @@ -1097,9 +2077,11 @@ enum { SSL_CIPHER_LIST, SSL_PROTOCOL_VERSION, SSL_SHORT_TRUST, + #if defined(USE_WEBSOCKET) WEBSOCKET_TIMEOUT, #endif + DECODE_URL, #if defined(USE_LUA) @@ -1117,16 +2099,36 @@ enum { #if defined(USE_LUA) && defined(USE_WEBSOCKET) LUA_WEBSOCKET_EXTENSIONS, #endif + ACCESS_CONTROL_ALLOW_ORIGIN, + ACCESS_CONTROL_ALLOW_METHODS, + ACCESS_CONTROL_ALLOW_HEADERS, ERROR_PAGES, CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the - * socket option typedef TCP_NODELAY. */ + * socket option typedef TCP_NODELAY. */ #if !defined(NO_CACHING) STATIC_FILE_MAX_AGE, #endif - VALIDATE_HTTP_METHOD, - CANONICALIZE_URL_PATH, +#if !defined(NO_SSL) + STRICT_HTTPS_MAX_AGE, +#endif +#if defined(__linux__) + ALLOW_SENDFILE_CALL, +#endif +#if defined(_WIN32) + CASE_SENSITIVE_FILES, +#endif +#if defined(USE_LUA) + LUA_BACKGROUND_SCRIPT, + LUA_BACKGROUND_SCRIPT_PARAMS, +#endif + ADDITIONAL_HEADER, + MAX_REQUEST_SIZE, + ALLOW_INDEX_SCRIPT_SUB_RES, + VALIDATE_HTTP_METHOD, + CANONICALIZE_URL_PATH, + ALLOW_UNICODE_IN_URLS, NUM_OPTIONS }; @@ -1134,38 +2136,45 @@ enum { /* Config option name, config types, default value */ static struct mg_option config_options[] = { {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"}, - {"cgi_environment", CONFIG_TYPE_STRING, NULL}, + {"cgi_environment", CONFIG_TYPE_STRING_LIST, NULL}, {"put_delete_auth_file", CONFIG_TYPE_FILE, NULL}, {"cgi_interpreter", CONFIG_TYPE_FILE, NULL}, - {"protect_uri", CONFIG_TYPE_STRING, NULL}, + {"protect_uri", CONFIG_TYPE_STRING_LIST, NULL}, {"authentication_domain", CONFIG_TYPE_STRING, "mydomain.com"}, {"enable_auth_domain_check", CONFIG_TYPE_BOOLEAN, "yes"}, {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"}, - {"throttle", CONFIG_TYPE_STRING, NULL}, + {"throttle", CONFIG_TYPE_STRING_LIST, NULL}, {"access_log_file", CONFIG_TYPE_FILE, NULL}, {"enable_directory_listing", CONFIG_TYPE_BOOLEAN, "yes"}, {"error_log_file", CONFIG_TYPE_FILE, NULL}, {"global_auth_file", CONFIG_TYPE_FILE, NULL}, {"index_files", - CONFIG_TYPE_STRING, + CONFIG_TYPE_STRING_LIST, #ifdef USE_LUA - "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi," + "index.xhtml,index.html,index.htm," + "index.lp,index.lsp,index.lua,index.cgi," "index.shtml,index.php"}, #else "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"}, #endif {"enable_keep_alive", CONFIG_TYPE_BOOLEAN, "no"}, - {"access_control_list", CONFIG_TYPE_STRING, NULL}, - {"extra_mime_types", CONFIG_TYPE_STRING, NULL}, - {"listening_ports", CONFIG_TYPE_STRING, "8080"}, + {"access_control_list", CONFIG_TYPE_STRING_LIST, NULL}, + {"extra_mime_types", CONFIG_TYPE_STRING_LIST, NULL}, + {"listening_ports", CONFIG_TYPE_STRING_LIST, "8080"}, {"document_root", CONFIG_TYPE_DIRECTORY, NULL}, {"ssl_certificate", CONFIG_TYPE_FILE, NULL}, + {"ssl_certificate_chain", CONFIG_TYPE_FILE, NULL}, {"num_threads", CONFIG_TYPE_NUMBER, "50"}, {"run_as_user", CONFIG_TYPE_STRING, NULL}, - {"url_rewrite_patterns", CONFIG_TYPE_STRING, NULL}, + {"url_rewrite_patterns", CONFIG_TYPE_STRING_LIST, NULL}, {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN, NULL}, {"request_timeout_ms", CONFIG_TYPE_NUMBER, "30000"}, + {"keep_alive_timeout_ms", CONFIG_TYPE_NUMBER, "500"}, + {"linger_timeout_ms", CONFIG_TYPE_NUMBER, NULL}, + + /* TODO(Feature): this is no longer a boolean, but yes/no/optional */ {"ssl_verify_peer", CONFIG_TYPE_BOOLEAN, "no"}, + {"ssl_ca_path", CONFIG_TYPE_DIRECTORY, NULL}, {"ssl_ca_file", CONFIG_TYPE_FILE, NULL}, {"ssl_verify_depth", CONFIG_TYPE_NUMBER, "9"}, @@ -1196,24 +2205,45 @@ static struct mg_option config_options[] = { {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"}, #endif {"access_control_allow_origin", CONFIG_TYPE_STRING, "*"}, + {"access_control_allow_methods", CONFIG_TYPE_STRING, "*"}, + {"access_control_allow_headers", CONFIG_TYPE_STRING, "*"}, {"error_pages", CONFIG_TYPE_DIRECTORY, NULL}, {"tcp_nodelay", CONFIG_TYPE_NUMBER, "0"}, #if !defined(NO_CACHING) {"static_file_max_age", CONFIG_TYPE_NUMBER, "3600"}, #endif +#if !defined(NO_SSL) + {"strict_transport_security_max_age", CONFIG_TYPE_NUMBER, NULL}, +#endif +#if defined(__linux__) + {"allow_sendfile_call", CONFIG_TYPE_BOOLEAN, "yes"}, +#endif +#if defined(_WIN32) + {"case_sensitive", CONFIG_TYPE_BOOLEAN, "no"}, +#endif +#if defined(USE_LUA) + {"lua_background_script", CONFIG_TYPE_FILE, NULL}, + {"lua_background_script_params", CONFIG_TYPE_STRING_LIST, NULL}, +#endif + {"additional_header", CONFIG_TYPE_STRING_MULTILINE, NULL}, + {"max_request_size", CONFIG_TYPE_NUMBER, "16384"}, + {"allow_index_script_resource", CONFIG_TYPE_BOOLEAN, "no"}, {"validate_http_method", CONFIG_TYPE_BOOLEAN, "yes"}, {"canonicalize_url_path", CONFIG_TYPE_BOOLEAN, "yes"}, - + {"allow_unicode_in_urls", CONFIG_TYPE_BOOLEAN, "no"}, {NULL, CONFIG_TYPE_UNKNOWN, NULL}}; + /* Check if the config_options and the corresponding enum have compatible * sizes. */ mg_static_assert((sizeof(config_options) / sizeof(config_options[0])) == (NUM_OPTIONS + 1), "config_options and enum not sync"); + enum { REQUEST_HANDLER, WEBSOCKET_HANDLER, AUTH_HANDLER }; + struct mg_handler_info { /* Name/Pattern of the URI. */ char *uri; @@ -1231,6 +2261,9 @@ struct mg_handler_info { mg_websocket_data_handler data_handler; mg_websocket_close_handler close_handler; + /* accepted subprotocols for ws/wss requests. */ + struct mg_websocket_subprotocols *subprotocols; + /* Handler for authorization requests */ mg_authorization_handler auth_handler; @@ -1241,35 +2274,53 @@ struct mg_handler_info { struct mg_handler_info *next; }; + +enum { + CONTEXT_INVALID, + CONTEXT_SERVER, + CONTEXT_HTTP_CLIENT, + CONTEXT_WS_CLIENT +}; + + struct mg_context { volatile int stop_flag; /* Should we stop event loop */ SSL_CTX *ssl_ctx; /* SSL context */ char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */ struct mg_callbacks callbacks; /* User-defined callback function */ void *user_data; /* User-defined data */ - int context_type; /* 1 = server context, 2 = client context */ + int context_type; /* See CONTEXT_* above */ struct socket *listening_sockets; - in_port_t *listening_ports; + struct pollfd *listening_socket_fds; unsigned int num_listening_sockets; - volatile int - running_worker_threads; /* Number of currently running worker threads */ pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */ - pthread_cond_t thread_cond; /* Condvar for tracking workers terminations */ +#ifdef ALTERNATIVE_QUEUE + struct socket *client_socks; + void **client_wait_events; +#else struct socket queue[MGSQLEN]; /* Accepted sockets */ volatile int sq_head; /* Head of the socket queue */ volatile int sq_tail; /* Tail of the socket queue */ pthread_cond_t sq_full; /* Signaled when socket is produced */ pthread_cond_t sq_empty; /* Signaled when socket is consumed */ - pthread_t masterthreadid; /* The master thread ID */ - unsigned int - cfg_worker_threads; /* The number of configured worker threads. */ - pthread_t *workerthreadids; /* The worker thread IDs */ +#endif - time_t start_time; /* Server start time, used for authentication */ - uint64_t auth_nonce_mask; /* Mask for all nonce values */ + unsigned int max_request_size; /* The max request size */ + + pthread_t masterthreadid; /* The master thread ID */ + unsigned int + cfg_worker_threads; /* The number of configured worker threads. */ + pthread_t *worker_threadids; /* The worker thread IDs */ + struct mg_connection *worker_connections; /* The connection struct, pre- + * allocated for each worker */ + + time_t start_time; /* Server start time, used for authentication + * and for diagnstics. */ + + uint64_t auth_nonce_mask; /* Mask for all nonce values */ pthread_mutex_t nonce_mutex; /* Protects nonce_count */ unsigned long nonce_count; /* Used nonces, used for authentication */ @@ -1283,15 +2334,59 @@ struct mg_context { struct mg_shared_lua_websocket_list *shared_lua_websockets; #endif -#ifdef USE_TIMERS +#if defined(USE_TIMERS) struct ttimers *timers; #endif + +#if defined(USE_LUA) + void *lua_background_state; +#endif + +#if defined(USE_SERVER_STATS) + int active_connections; + int max_connections; + int64_t total_connections; + int64_t total_requests; + struct mg_memory_stat ctx_memory; + int64_t total_data_read; + int64_t total_data_written; +#endif }; +#if defined(USE_SERVER_STATS) +static struct mg_memory_stat mg_common_memory = {0, 0, 0}; + +static struct mg_memory_stat * +get_memory_stat(struct mg_context *ctx) +{ + if (ctx) { + return &(ctx->ctx_memory); + } + return &mg_common_memory; +} +#endif + +enum { + CONNECTION_TYPE_INVALID, + CONNECTION_TYPE_REQUEST, + CONNECTION_TYPE_RESPONSE +}; + struct mg_connection { + int connection_type; /* see CONNECTION_TYPE_* above */ + struct mg_request_info request_info; + struct mg_response_info response_info; + struct mg_context *ctx; + +#if defined(USE_SERVER_STATS) + int conn_state; /* 0 = undef, numerical value may change in different + * versions. For the current definition, see + * mg_get_connection_info_impl */ +#endif + SSL *ssl; /* SSL descriptor */ SSL_CTX *client_ssl_ctx; /* SSL context for client connections */ struct socket client; /* Connected client */ @@ -1302,24 +2397,32 @@ struct mg_connection { int64_t num_bytes_sent; /* Total bytes sent to client */ int64_t content_len; /* Content-Length header value */ int64_t consumed_content; /* How many bytes of content have been read */ - int is_chunked; /* Transfer-Encoding is chunked: 0=no, 1=yes: - * data available, 2: all data read */ + int is_chunked; /* Transfer-Encoding is chunked: + * 0 = not chunked, + * 1 = chunked, do data read yet, + * 2 = chunked, some data read, + * 3 = chunked, all data read + */ size_t chunk_remainder; /* Unread data from the last chunk */ char *buf; /* Buffer for received data */ char *path_info; /* PATH_INFO part of the URL */ int must_close; /* 1 if connection must be closed */ + int accept_gzip; /* 1 if gzip encoding is accepted */ int in_error_handler; /* 1 if in handler for user defined error * pages */ - int internal_error; /* 1 if an error occured while processing the - * request */ +#if defined(USE_WEBSOCKET) + int in_websocket_handling; /* 1 if in read_websocket */ +#endif + int handled_requests; /* Number of requests handled by this connection + */ + int buf_size; /* Buffer size */ + int request_len; /* Size of the request + headers in a buffer */ + int data_len; /* Total size of data in a buffer */ + int status_code; /* HTTP reply status code, e.g. 200 */ + int throttle; /* Throttling, bytes/sec. <= 0 means no + * throttle */ - int buf_size; /* Buffer size */ - int request_len; /* Size of the request + headers in a buffer */ - int data_len; /* Total size of data in a buffer */ - int status_code; /* HTTP reply status code, e.g. 200 */ - int throttle; /* Throttling, bytes/sec. <= 0 means no - * throttle */ time_t last_throttle_time; /* Last time throttled data was sent */ int64_t last_throttle_bytes; /* Bytes sent this second */ pthread_mutex_t mutex; /* Used by mg_(un)lock_connection to ensure @@ -1327,27 +2430,16 @@ struct mg_connection { #if defined(USE_LUA) && defined(USE_WEBSOCKET) void *lua_websocket_state; /* Lua_State for a websocket connection */ #endif + + int thread_index; /* Thread index within ctx */ }; -static pthread_key_t sTlsKey; /* Thread local storage index */ -static int sTlsInit = 0; -static int thread_idx_max = 0; - - -struct mg_workerTLS { - int is_master; - unsigned long thread_idx; -#if defined(_WIN32) && !defined(__SYMBIAN32__) - HANDLE pthread_cond_helper_mutex; -#endif -}; - /* Directory entry */ struct de { struct mg_connection *conn; char *file_name; - struct file file; + struct mg_file_stat file; }; @@ -1358,43 +2450,6 @@ static int is_websocket_protocol(const struct mg_connection *conn); #endif -static int -mg_atomic_inc(volatile int *addr) -{ - int ret; -#if defined(_WIN32) && !defined(__SYMBIAN32__) - /* Depending on the SDK, this function uses either - * (volatile unsigned int *) or (volatile LONG *), - * so whatever you use, the other SDK is likely to raise a warning. */ - ret = InterlockedIncrement((volatile long *)addr); -#elif defined(__GNUC__) \ - && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) - ret = __sync_add_and_fetch(addr, 1); -#else - ret = (++(*addr)); -#endif - return ret; -} - - -static int -mg_atomic_dec(volatile int *addr) -{ - int ret; -#if defined(_WIN32) && !defined(__SYMBIAN32__) - /* Depending on the SDK, this function uses either - * (volatile unsigned int *) or (volatile LONG *), - * so whatever you use, the other SDK is likely to raise a warning. */ - ret = InterlockedDecrement((volatile long *)addr); -#elif defined(__GNUC__) \ - && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) - ret = __sync_sub_and_fetch(addr, 1); -#else - ret = (--(*addr)); -#endif - return ret; -} - #if !defined(NO_THREAD_NAME) #if defined(_WIN32) && defined(_MSC_VER) /* Set the thread name for debugging purposes in Visual Studio @@ -1408,9 +2463,210 @@ typedef struct tagTHREADNAME_INFO { DWORD dwFlags; /* Reserved for future use, must be zero. */ } THREADNAME_INFO; #pragma pack(pop) + #elif defined(__linux__) + #include #include +#ifdef ALTERNATIVE_QUEUE +#include +#endif /* ALTERNATIVE_QUEUE */ + + +#if defined(ALTERNATIVE_QUEUE) + + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +/* For every system, "(sizeof(int) == sizeof(void *))" is either always + * true or always false. One of the two branches is unreachable in any case. + * Unfortunately the C standard does not define a way to check this at + * compile time, since the #if preprocessor conditions can not use the sizeof + * operator as an argument. */ +#endif + +#if defined(__GNUC__) || defined(__MINGW32__) +/* GCC does not realize one branch is unreachable, so it raises some + * pointer cast warning within the unreachable branch. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" +#endif + + +static void * +event_create(void) +{ + int evhdl = eventfd(0, EFD_CLOEXEC); + int *ret; + + if (evhdl == -1) { + /* Linux uses -1 on error, Windows NULL. */ + /* However, Linux does not return 0 on success either. */ + return 0; + } + if (sizeof(int) == sizeof(void *)) { + ret = (void *)evhdl; + } else { + ret = (int *)mg_malloc(sizeof(int)); + if (ret) { + *ret = evhdl; + } else { + (void)close(evhdl); + } + } + + return (void *)ret; +} + + +static int +event_wait(void *eventhdl) +{ + uint64_t u; + int evhdl, s; + + if (sizeof(int) == sizeof(void *)) { + evhdl = (int)eventhdl; + } else { + if (!eventhdl) { + /* error */ + return 0; + } + evhdl = *(int *)eventhdl; + } + + s = (int)read(evhdl, &u, sizeof(u)); + if (s != sizeof(uint64_t)) { + /* error */ + return 0; + } + (void)u; /* the value is not required */ + return 1; +} + + +static int +event_signal(void *eventhdl) +{ + uint64_t u = 1; + int evhdl, s; + + if (sizeof(int) == sizeof(void *)) { + evhdl = (int)eventhdl; + } else { + if (!eventhdl) { + /* error */ + return 0; + } + evhdl = *(int *)eventhdl; + } + + s = (int)write(evhdl, &u, sizeof(u)); + if (s != sizeof(uint64_t)) { + /* error */ + return 0; + } + return 1; +} + + +static void +event_destroy(void *eventhdl) +{ + int evhdl; + + if (sizeof(int) == sizeof(void *)) { + evhdl = (int)eventhdl; + close(evhdl); + } else { + if (!eventhdl) { + /* error */ + return; + } + evhdl = *(int *)eventhdl; + close(evhdl); + mg_free(eventhdl); + } +} + + +#if defined(__GNUC__) || defined(__MINGW32__) +#pragma GCC diagnostic pop +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#endif + + +#if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE) + +struct posix_event { + pthread_mutex_t mutex; + pthread_cond_t cond; +}; + + +static void * +event_create(void) +{ + struct posix_event *ret = mg_malloc(sizeof(struct posix_event)); + if (ret == 0) { + /* out of memory */ + return 0; + } + if (0 != pthread_mutex_init(&(ret->mutex), NULL)) { + /* pthread mutex not available */ + mg_free(ret); + return 0; + } + if (0 != pthread_cond_init(&(ret->cond), NULL)) { + /* pthread cond not available */ + pthread_mutex_destroy(&(ret->mutex)); + mg_free(ret); + return 0; + } + return (void *)ret; +} + + +static int +event_wait(void *eventhdl) +{ + struct posix_event *ev = (struct posix_event *)eventhdl; + pthread_mutex_lock(&(ev->mutex)); + pthread_cond_wait(&(ev->cond), &(ev->mutex)); + pthread_mutex_unlock(&(ev->mutex)); + return 1; +} + + +static int +event_signal(void *eventhdl) +{ + struct posix_event *ev = (struct posix_event *)eventhdl; + pthread_mutex_lock(&(ev->mutex)); + pthread_cond_signal(&(ev->cond)); + pthread_mutex_unlock(&(ev->mutex)); + return 1; +} + + +static void +event_destroy(void *eventhdl) +{ + struct posix_event *ev = (struct posix_event *)eventhdl; + pthread_cond_destroy(&(ev->cond)); + pthread_mutex_destroy(&(ev->mutex)); + mg_free(ev); +} #endif @@ -1487,88 +2743,206 @@ mg_get_valid_options(void) } +/* Do not open file (used in is_file_in_memory) */ +#define MG_FOPEN_MODE_NONE (0) + +/* Open file for read only access */ +#define MG_FOPEN_MODE_READ (1) + +/* Open file for writing, create and overwrite */ +#define MG_FOPEN_MODE_WRITE (2) + +/* Open file for writing, create and append */ +#define MG_FOPEN_MODE_APPEND (4) + + +/* If a file is in memory, set all "stat" members and the membuf pointer of + * output filep and return 1, otherwise return 0 and don't modify anything. + */ static int -is_file_in_memory(const struct mg_connection *conn, - const char *path, - struct file *filep) +open_file_in_memory(const struct mg_connection *conn, + const char *path, + struct mg_file *filep, + int mode) { +#if defined(MG_USE_OPEN_FILE) + size_t size = 0; - if (!conn || !filep) { + const char *buf = NULL; + if (!conn) { + return 0; + } + + if ((mode != MG_FOPEN_MODE_NONE) && (mode != MG_FOPEN_MODE_READ)) { return 0; } if (conn->ctx->callbacks.open_file) { - filep->membuf = conn->ctx->callbacks.open_file(conn, path, &size); - if (filep->membuf != NULL) { - /* NOTE: override filep->size only on success. Otherwise, it might + buf = conn->ctx->callbacks.open_file(conn, path, &size); + if (buf != NULL) { + if (filep == NULL) { + /* This is a file in memory, but we cannot store the + * properties + * now. + * Called from "is_file_in_memory" function. */ + return 1; + } + + /* NOTE: override filep->size only on success. Otherwise, it + * might * break constructs like if (!mg_stat() || !mg_fopen()) ... */ - filep->size = size; + filep->access.membuf = buf; + filep->access.fp = NULL; + + /* Size was set by the callback */ + filep->stat.size = size; + + /* Assume the data may change during runtime by setting + * last_modified = now */ + filep->stat.last_modified = time(NULL); + + filep->stat.is_directory = 0; + filep->stat.is_gzipped = 0; } } - return filep->membuf != NULL; + return (buf != NULL); + +#else + (void)conn; + (void)path; + (void)filep; + (void)mode; + + return 0; + +#endif } static int -is_file_opened(const struct file *filep) +is_file_in_memory(const struct mg_connection *conn, const char *path) { - if (!filep) { + return open_file_in_memory(conn, path, NULL, MG_FOPEN_MODE_NONE); +} + + +static int +is_file_opened(const struct mg_file_access *fileacc) +{ + if (!fileacc) { return 0; } - - return filep->membuf != NULL || filep->fp != NULL; + return (fileacc->membuf != NULL) || (fileacc->fp != NULL); } +static int mg_stat(const struct mg_connection *conn, + const char *path, + struct mg_file_stat *filep); + + /* mg_fopen will open a file either in memory or on the disk. * The input parameter path is a string in UTF-8 encoding. - * The input parameter mode is the same as for fopen. - * Either fp or membuf will be set in the output struct filep. + * The input parameter mode is MG_FOPEN_MODE_* + * On success, either fp or membuf will be set in the output + * struct file. All status members will also be set. * The function returns 1 on success, 0 on error. */ static int mg_fopen(const struct mg_connection *conn, const char *path, - const char *mode, - struct file *filep) + int mode, + struct mg_file *filep) { - struct stat st; + int found; if (!filep) { return 0; } + filep->access.fp = NULL; + filep->access.membuf = NULL; - /* TODO (high): mg_fopen should only open a file, while mg_stat should - * only get the file status. They should not work on different members of - * the same structure (bad cohesion). */ - memset(filep, 0, sizeof(*filep)); + if (!is_file_in_memory(conn, path)) { - if (stat(path, &st) == 0) { - filep->size = (uint64_t)(st.st_size); - } + /* filep is initialized in mg_stat: all fields with memset to, + * some fields like size and modification date with values */ + found = mg_stat(conn, path, &(filep->stat)); + + if ((mode == MG_FOPEN_MODE_READ) && (!found)) { + /* file does not exist and will not be created */ + return 0; + } - if (!is_file_in_memory(conn, path, filep)) { #ifdef _WIN32 - wchar_t wbuf[PATH_MAX], wmode[20]; - path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf)); - MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode)); - filep->fp = _wfopen(wbuf, wmode); + { + wchar_t wbuf[PATH_MAX]; + path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf)); + switch (mode) { + case MG_FOPEN_MODE_READ: + filep->access.fp = _wfopen(wbuf, L"rb"); + break; + case MG_FOPEN_MODE_WRITE: + filep->access.fp = _wfopen(wbuf, L"wb"); + break; + case MG_FOPEN_MODE_APPEND: + filep->access.fp = _wfopen(wbuf, L"ab"); + break; + } + } #else /* Linux et al already use unicode. No need to convert. */ - filep->fp = fopen(path, mode); + switch (mode) { + case MG_FOPEN_MODE_READ: + filep->access.fp = fopen(path, "r"); + break; + case MG_FOPEN_MODE_WRITE: + filep->access.fp = fopen(path, "w"); + break; + case MG_FOPEN_MODE_APPEND: + filep->access.fp = fopen(path, "a"); + break; + } + #endif + if (!found) { + /* File did not exist before fopen was called. + * Maybe it has been created now. Get stat info + * like creation time now. */ + found = mg_stat(conn, path, &(filep->stat)); + (void)found; + } + + /* file is on disk */ + return (filep->access.fp != NULL); + + } else { + /* is_file_in_memory returned true */ + if (open_file_in_memory(conn, path, filep, mode)) { + /* file is in memory */ + return (filep->access.membuf != NULL); + } } - return is_file_opened(filep); + /* Open failed */ + return 0; } -static void -mg_fclose(struct file *filep) +/* return 0 on success, just like fclose */ +static int +mg_fclose(struct mg_file_access *fileacc) { - if (filep != NULL && filep->fp != NULL) { - fclose(filep->fp); + int ret = -1; + if (fileacc != NULL) { + if (fileacc->fp != NULL) { + ret = fclose(fileacc->fp); + } else if (fileacc->membuf != NULL) { + ret = 0; + } + /* reset all members of fileacc */ + memset(fileacc, 0, sizeof(*fileacc)); } + return ret; } @@ -1667,6 +3041,9 @@ mg_vsnprintf(const struct mg_connection *conn, int n, ok; if (buflen == 0) { + if (truncated) { + *truncated = 1; + } return; } @@ -1779,6 +3156,8 @@ mg_get_user_connection_data(const struct mg_connection *conn) } +#if defined(MG_LEGACY_INTERFACE) +/* Deprecated: Use mg_get_server_ports instead. */ size_t mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl) { @@ -1788,10 +3167,17 @@ mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl) } for (i = 0; i < size && i < ctx->num_listening_sockets; i++) { ssl[i] = ctx->listening_sockets[i].is_ssl; - ports[i] = ctx->listening_ports[i]; + ports[i] = +#if defined(USE_IPV6) + (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) + ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port) + : +#endif + ntohs(ctx->listening_sockets[i].lsa.sin.sin_port); } return i; } +#endif int @@ -1808,13 +3194,19 @@ mg_get_server_ports(const struct mg_context *ctx, if (!ctx) { return -1; } - if (!ctx->listening_sockets || !ctx->listening_ports) { + if (!ctx->listening_sockets) { return -1; } for (i = 0; (i < size) && (i < (int)ctx->num_listening_sockets); i++) { - ports[cnt].port = ctx->listening_ports[i]; + ports[cnt].port = +#if defined(USE_IPV6) + (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) + ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port) + : +#endif + ntohs(ctx->listening_sockets[i].lsa.sin.sin_port); ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl; ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir; @@ -1897,7 +3289,7 @@ mg_cry(const struct mg_connection *conn, const char *fmt, ...) { char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN]; va_list ap; - struct file fi; + struct mg_file fi; time_t timestamp; va_start(ap, fmt); @@ -1905,6 +3297,8 @@ mg_cry(const struct mg_connection *conn, const char *fmt, ...) va_end(ap); buf[sizeof(buf) - 1] = 0; + DEBUG_TRACE("mg_cry: %s", buf); + if (!conn) { puts(buf); return; @@ -1917,36 +3311,41 @@ mg_cry(const struct mg_connection *conn, const char *fmt, ...) || (conn->ctx->callbacks.log_message(conn, buf) == 0)) { if (conn->ctx->config[ERROR_LOG_FILE] != NULL) { - if (mg_fopen(conn, conn->ctx->config[ERROR_LOG_FILE], "a+", &fi) - == 0) { - fi.fp = NULL; + if (mg_fopen(conn, + conn->ctx->config[ERROR_LOG_FILE], + MG_FOPEN_MODE_APPEND, + &fi) == 0) { + fi.access.fp = NULL; } } else { - fi.fp = NULL; + fi.access.fp = NULL; } - if (fi.fp != NULL) { - flockfile(fi.fp); + if (fi.access.fp != NULL) { + flockfile(fi.access.fp); timestamp = time(NULL); sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa); - fprintf(fi.fp, + fprintf(fi.access.fp, "[%010lu] [error] [client %s] ", (unsigned long)timestamp, src_addr); if (conn->request_info.request_method != NULL) { - fprintf(fi.fp, + fprintf(fi.access.fp, "%s %s: ", conn->request_info.request_method, - conn->request_info.request_uri); + conn->request_info.request_uri + ? conn->request_info.request_uri + : ""); } - fprintf(fi.fp, "%s", buf); - fputc('\n', fi.fp); - fflush(fi.fp); - funlockfile(fi.fp); - mg_fclose(&fi); + fprintf(fi.access.fp, "%s", buf); + fputc('\n', fi.access.fp); + fflush(fi.access.fp); + funlockfile(fi.access.fp); + (void)mg_fclose(&fi.access); /* Ignore errors. We can't call + * mg_cry here anyway ;-) */ } } } @@ -1954,7 +3353,7 @@ mg_cry(const struct mg_connection *conn, const char *fmt, ...) void mg_set_http_status(struct mg_connection *conn, int status) { - conn->status_code = status; + conn->status_code = status; } /* Return fake connection structure. Used for logging, if connection @@ -1981,10 +3380,150 @@ mg_get_request_info(const struct mg_connection *conn) if (!conn) { return NULL; } +#if 1 /* TODO: deal with legacy */ + if (conn->connection_type == CONNECTION_TYPE_RESPONSE) { + static char txt[16]; + sprintf(txt, "%03i", conn->response_info.status_code); + + ((struct mg_connection *)conn)->request_info.local_uri = + ((struct mg_connection *)conn)->request_info.request_uri = + txt; /* TODO: not thread safe */ + + ((struct mg_connection *)conn)->request_info.num_headers = + conn->response_info.num_headers; + memcpy(((struct mg_connection *)conn)->request_info.http_headers, + conn->response_info.http_headers, + sizeof(conn->response_info.http_headers)); + } else +#endif + if (conn->connection_type != CONNECTION_TYPE_REQUEST) { + return NULL; + } return &conn->request_info; } +const struct mg_response_info * +mg_get_response_info(const struct mg_connection *conn) +{ + if (!conn) { + return NULL; + } + if (conn->connection_type != CONNECTION_TYPE_RESPONSE) { + return NULL; + } + return &conn->response_info; +} + + +static const char * +get_proto_name(const struct mg_connection *conn) +{ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +/* Depending on USE_WEBSOCKET and NO_SSL, some oft the protocols might be + * not supported. Clang raises an "unreachable code" warning for parts of ?: + * unreachable, but splitting into four different #ifdef clauses here is more + * complicated. + */ +#endif + + const struct mg_request_info *ri = &conn->request_info; + + const char *proto = + (is_websocket_protocol(conn) ? (ri->is_ssl ? "wss" : "ws") + : (ri->is_ssl ? "https" : "http")); + + return proto; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +} + + +int +mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen) +{ + if ((buflen < 1) || (buf == 0) || (conn == 0)) { + return -1; + } else { + + int truncated = 0; + const struct mg_request_info *ri = &conn->request_info; + + const char *proto = get_proto_name(conn); + + if (ri->local_uri == NULL) { + return -1; + } + + if ((ri->request_uri != NULL) + && strcmp(ri->local_uri, ri->request_uri)) { + mg_snprintf(conn, + &truncated, + buf, + buflen, + "%s://%s", + proto, + ri->request_uri); + if (truncated) { + return -1; + } + return 0; + } else { + +#if defined(USE_IPV6) + int is_ipv6 = (conn->client.lsa.sa.sa_family == AF_INET6); + int port = is_ipv6 ? htons(conn->client.lsa.sin6.sin6_port) + : htons(conn->client.lsa.sin.sin_port); +#else + int port = htons(conn->client.lsa.sin.sin_port); +#endif + int def_port = ri->is_ssl ? 443 : 80; + int auth_domain_check_enabled = + conn->ctx->config[ENABLE_AUTH_DOMAIN_CHECK] + && (!mg_strcasecmp(conn->ctx->config[ENABLE_AUTH_DOMAIN_CHECK], + "yes")); + const char *server_domain = + conn->ctx->config[AUTHENTICATION_DOMAIN]; + + char portstr[16]; + char server_ip[48]; + + if (port != def_port) { + sprintf(portstr, ":%u", (unsigned)port); + } else { + portstr[0] = 0; + } + + if (!auth_domain_check_enabled || !server_domain) { + + sockaddr_to_string(server_ip, + sizeof(server_ip), + &conn->client.lsa); + + server_domain = server_ip; + } + + mg_snprintf(conn, + &truncated, + buf, + buflen, + "%s://%s%s%s", + proto, + server_domain, + portstr, + ri->local_uri); + if (truncated) { + return -1; + } + return 0; + } + } +} + struct sockaddr * mg_get_local_addr(struct mg_connection *conn) { @@ -1994,7 +3533,8 @@ mg_get_local_addr(struct mg_connection *conn) /* Skip the characters until one of the delimiters characters found. * 0-terminate resulting word. Skip the delimiter and following whitespaces. - * Advance pointer to buffer to the next word. Return found 0-terminated word. + * Advance pointer to buffer to the next word. Return found 0-terminated + * word. * Delimiters can be quoted with quotechar. */ static char * skip_quoted(char **buf, @@ -2011,7 +3551,8 @@ skip_quoted(char **buf, if (end_word > begin_word) { p = end_word - 1; while (*p == quotechar) { - /* While the delimiter is quoted, look for the next delimiter. */ + /* While the delimiter is quoted, look for the next delimiter. + */ /* This happens, e.g., in calls from parse_auth_header, * if the user name contains a " character. */ @@ -2034,7 +3575,22 @@ skip_quoted(char **buf, if (*end_word == '\0') { *buf = end_word; } else { - end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace); + +#if defined(__GNUC__) || defined(__MINGW32__) +/* Disable spurious conversion warning for GCC */ +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) || defined(__MINGW32__) */ + + end_whitespace = end_word + strspn(&end_word[1], whitespace) + 1; + +#if defined(__GNUC__) || defined(__MINGW32__) +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic pop +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) || defined(__MINGW32__) */ for (p = end_word; p < end_whitespace; p++) { *p = '\0'; @@ -2047,25 +3603,14 @@ skip_quoted(char **buf, } -/* Simplified version of skip_quoted without quote char - * and whitespace == delimiters */ -static char * -skip(char **buf, const char *delimiters) -{ - return skip_quoted(buf, delimiters, delimiters, 0); -} - - /* Return HTTP header value, or NULL if not found. */ static const char * -get_header(const struct mg_request_info *ri, const char *name) +get_header(const struct mg_header *hdr, int num_hdr, const char *name) { int i; - if (ri) { - for (i = 0; i < ri->num_headers; i++) { - if (!mg_strcasecmp(name, ri->http_headers[i].name)) { - return ri->http_headers[i].value; - } + for (i = 0; i < num_hdr; i++) { + if (!mg_strcasecmp(name, hdr[i].name)) { + return hdr[i].value; } } @@ -2073,6 +3618,29 @@ get_header(const struct mg_request_info *ri, const char *name) } +#if defined(USE_WEBSOCKET) +/* Retrieve requested HTTP header multiple values, and return the number of + * found occurences */ +static int +get_req_headers(const struct mg_request_info *ri, + const char *name, + const char **output, + int output_max_size) +{ + int i; + int cnt = 0; + if (ri) { + for (i = 0; i < ri->num_headers && cnt < output_max_size; i++) { + if (!mg_strcasecmp(name, ri->http_headers[i].name)) { + output[cnt++] = ri->http_headers[i].value; + } + } + } + return cnt; +} +#endif + + const char * mg_get_header(const struct mg_connection *conn, const char *name) { @@ -2080,7 +3648,34 @@ mg_get_header(const struct mg_connection *conn, const char *name) return NULL; } - return get_header(&conn->request_info, name); + if (conn->connection_type == CONNECTION_TYPE_REQUEST) { + return get_header(conn->request_info.http_headers, + conn->request_info.num_headers, + name); + } + if (conn->connection_type == CONNECTION_TYPE_RESPONSE) { + return get_header(conn->response_info.http_headers, + conn->request_info.num_headers, + name); + } + return NULL; +} + + +static const char * +get_http_version(const struct mg_connection *conn) +{ + if (!conn) { + return NULL; + } + + if (conn->connection_type == CONNECTION_TYPE_REQUEST) { + return conn->request_info.http_version; + } + if (conn->connection_type == CONNECTION_TYPE_RESPONSE) { + return conn->response_info.http_version; + } + return NULL; } @@ -2098,51 +3693,53 @@ next_option(const char *list, struct vec *val, struct vec *eq_val) reparse: if (val == NULL || list == NULL || *list == '\0') { /* End of the list */ - list = NULL; + return NULL; + } + + /* Skip over leading LWS */ + while (*list == ' ' || *list == '\t') + list++; + + val->ptr = list; + if ((list = strchr(val->ptr, ',')) != NULL) { + /* Comma found. Store length and shift the list ptr */ + val->len = ((size_t)(list - val->ptr)); + list++; } else { - /* Skip over leading LWS */ - while (*list == ' ' || *list == '\t') - list++; + /* This value is the last one */ + list = val->ptr + strlen(val->ptr); + val->len = ((size_t)(list - val->ptr)); + } - val->ptr = list; - if ((list = strchr(val->ptr, ',')) != NULL) { - /* Comma found. Store length and shift the list ptr */ - val->len = ((size_t)(list - val->ptr)); - list++; - } else { - /* This value is the last one */ - list = val->ptr + strlen(val->ptr); - val->len = ((size_t)(list - val->ptr)); - } + /* Adjust length for trailing LWS */ + end = (int)val->len - 1; + while (end >= 0 && ((val->ptr[end] == ' ') || (val->ptr[end] == '\t'))) + end--; + val->len = (size_t)(end + 1); - /* Adjust length for trailing LWS */ - end = (int)val->len - 1; - while (end >= 0 && (val->ptr[end] == ' ' || val->ptr[end] == '\t')) - end--; - val->len = (size_t)(end + 1); + if (val->len == 0) { + /* Ignore any empty entries. */ + goto reparse; + } - if (val->len == 0) { - /* Ignore any empty entries. */ - goto reparse; - } - - if (eq_val != NULL) { - /* Value has form "x=y", adjust pointers and lengths - * so that val points to "x", and eq_val points to "y". */ - eq_val->len = 0; - eq_val->ptr = (const char *)memchr(val->ptr, '=', val->len); - if (eq_val->ptr != NULL) { - eq_val->ptr++; /* Skip over '=' character */ - eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len; - val->len = ((size_t)(eq_val->ptr - val->ptr)) - 1; - } + if (eq_val != NULL) { + /* Value has form "x=y", adjust pointers and lengths + * so that val points to "x", and eq_val points to "y". */ + eq_val->len = 0; + eq_val->ptr = (const char *)memchr(val->ptr, '=', val->len); + if (eq_val->ptr != NULL) { + eq_val->ptr++; /* Skip over '=' character */ + eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len; + val->len = ((size_t)(eq_val->ptr - val->ptr)) - 1; } } return list; } -/* A helper function for checking if a comma separated list of values contains + +/* A helper function for checking if a comma separated list of values + * contains * the given option (case insensitvely). * 'header' can be NULL, in which case false is returned. */ static int @@ -2151,8 +3748,10 @@ header_has_option(const char *header, const char *option) struct vec opt_vec; struct vec eq_vec; + /* assert(option != NULL); assert(option[0] != '\0'); + */ while ((header = next_option(header, &opt_vec, &eq_vec)) != NULL) { if (mg_strncasecmp(option, opt_vec.ptr, opt_vec.len) == 0) @@ -2162,6 +3761,7 @@ header_has_option(const char *header, const char *option) return 0; } + /* Perform case-insensitive match of string against pattern */ static int match_prefix(const char *pattern, size_t pattern_len, const char *str) @@ -2172,17 +3772,17 @@ match_prefix(const char *pattern, size_t pattern_len, const char *str) if ((or_str = (const char *)memchr(pattern, '|', pattern_len)) != NULL) { res = match_prefix(pattern, (size_t)(or_str - pattern), str); - return res > 0 ? res : match_prefix(or_str + 1, - (size_t)((pattern + pattern_len) - - (or_str + 1)), - str); + return (res > 0) ? res : match_prefix(or_str + 1, + (size_t)((pattern + pattern_len) + - (or_str + 1)), + str); } - for (i = 0, j = 0; i < pattern_len; i++, j++) { - if (pattern[i] == '?' && str[j] != '\0') { + for (i = 0, j = 0; (i < pattern_len); i++, j++) { + if ((pattern[i] == '?') && (str[j] != '\0')) { continue; } else if (pattern[i] == '$') { - return str[j] == '\0' ? j : -1; + return (str[j] == '\0') ? j : -1; } else if (pattern[i] == '*') { i++; if (pattern[i] == '*') { @@ -2197,7 +3797,7 @@ match_prefix(const char *pattern, size_t pattern_len, const char *str) do { res = match_prefix(pattern + i, pattern_len - i, str + j + len); } while (res == -1 && len-- > 0); - return res == -1 ? -1 : j + res + len; + return (res == -1) ? -1 : j + res + len; } else if (lowercase(&pattern[i]) != lowercase(&str[j])) { return -1; } @@ -2212,18 +3812,38 @@ match_prefix(const char *pattern, size_t pattern_len, const char *str) static int should_keep_alive(const struct mg_connection *conn) { - if (conn != NULL) { - const char *http_version = conn->request_info.http_version; - const char *header = mg_get_header(conn, "Connection"); - if (conn->must_close || conn->internal_error || conn->status_code == 401 - || mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 - || (header != NULL && !header_has_option(header, "keep-alive")) - || (header == NULL && http_version - && 0 != strcmp(http_version, "1.1"))) { - return 0; + const char *http_version; + const char *header; + + /* First satisfy needs of the server */ + if ((conn == NULL) || conn->must_close) { + /* Close, if civetweb framework needs to close */ + return 0; + } + + if (mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0) { + /* Close, if keep alive is not enabled */ + return 0; + } + + /* Check explicit wish of the client */ + header = mg_get_header(conn, "Connection"); + if (header) { + /* If there is a connection header from the client, obey */ + if (header_has_option(header, "keep-alive")) { + return 1; } + return 0; + } + + /* Use default of the standard */ + http_version = get_http_version(conn); + if (http_version && (0 == strcmp(http_version, "1.1"))) { + /* HTTP 1.1 default is keep alive */ return 1; } + + /* HTTP 1.0 (and earlier) default is to close the connection */ return 0; } @@ -2238,16 +3858,6 @@ should_decode_url(const struct mg_connection *conn) return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0); } -static int -should_validate_http_method(const struct mg_connection *conn) -{ - if (!conn || !conn->ctx || !conn->ctx->config[VALIDATE_HTTP_METHOD]) { - return 1; - } - - return (mg_strcasecmp(conn->ctx->config[VALIDATE_HTTP_METHOD], "yes") == 0); -} - static const char * suggest_connection_header(const struct mg_connection *conn) @@ -2287,7 +3897,8 @@ send_static_cache_header(struct mg_connection *conn) * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */ /* See also https://www.mnot.net/cache_docs/ */ /* According to RFC 2616, Section 14.21, caching times should not exceed - * one year. A year with 365 days corresponds to 31536000 seconds, a leap + * one year. A year with 365 days corresponds to 31536000 seconds, a + * leap * year to 31622400 seconds. For the moment, we just send whatever has * been configured, still the behavior for >1 year should be considered * as undefined. */ @@ -2298,16 +3909,38 @@ send_static_cache_header(struct mg_connection *conn) } +static int +send_additional_header(struct mg_connection *conn) +{ + int i = 0; + const char *header = conn->ctx->config[ADDITIONAL_HEADER]; + +#if !defined(NO_SSL) + if (conn->ctx->config[STRICT_HTTPS_MAX_AGE]) { + int max_age = atoi(conn->ctx->config[STRICT_HTTPS_MAX_AGE]); + if (max_age >= 0) { + i += mg_printf(conn, + "Strict-Transport-Security: max-age=%u\r\n", + (unsigned)max_age); + } + } +#endif + + if (header && header[0]) { + i += mg_printf(conn, "%s\r\n", header); + } + + return i; +} + + static void handle_file_based_request(struct mg_connection *conn, const char *path, - struct file *filep); - -static int -mg_stat(struct mg_connection *conn, const char *path, struct file *filep); + struct mg_file *filep); const char * -mg_get_response_code_text(struct mg_connection *conn, int response_code) +mg_get_response_code_text(const struct mg_connection *conn, int response_code) { /* See IANA HTTP status code assignment: * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml @@ -2338,7 +3971,8 @@ mg_get_response_code_text(struct mg_connection *conn, int response_code) case 206: return "Partial Content"; /* RFC2616 Section 10.2.7 */ case 207: - return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1 */ + return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1 + */ case 208: return "Already Reported"; /* RFC5842 Section 7.1 */ @@ -2397,7 +4031,8 @@ mg_get_response_code_text(struct mg_connection *conn, int response_code) case 415: return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */ case 416: - return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17 */ + return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17 + */ case 417: return "Expectation Failed"; /* RFC2616 Section 10.4.18 */ @@ -2453,7 +4088,8 @@ mg_get_response_code_text(struct mg_connection *conn, int response_code) case 511: return "Network Authentication Required"; /* RFC 6585, Section 6 */ - /* Other status codes, not shown in the IANA HTTP status code assignment. + /* Other status codes, not shown in the IANA HTTP status code + * assignment. * E.g., "de facto" standards due to common use, ... */ case 418: return "I am a teapot"; /* RFC2324 Section 2.3.2 */ @@ -2500,21 +4136,16 @@ mg_get_response_code_text(struct mg_connection *conn, int response_code) } -static void send_http_error(struct mg_connection *, - int, - PRINTF_FORMAT_STRING(const char *fmt), - ...) PRINTF_ARGS(3, 4); - -static void -send_http_error(struct mg_connection *conn, int status, const char *fmt, ...) +void +mg_send_http_error(struct mg_connection *conn, int status, const char *fmt, ...) { char buf[MG_BUF_LEN]; va_list ap; - int len, i, page_handler_found, scope, truncated; + int len, i, page_handler_found, scope, truncated, has_body; char date[64]; time_t curtime = time(NULL); const char *error_handler = NULL; - struct file error_page_file = STRUCT_FILE_INITIALIZER; + struct mg_file error_page_file = STRUCT_FILE_INITIALIZER; const char *error_page_file_ext, *tstr; const char *status_text = mg_get_response_code_text(conn, status); @@ -2524,13 +4155,20 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...) } conn->status_code = status; - if (conn->in_error_handler || conn->ctx->callbacks.http_error == NULL + if (conn->in_error_handler || (conn->ctx->callbacks.http_error == NULL) || conn->ctx->callbacks.http_error(conn, status)) { - if (!conn->in_error_handler) { + + /* Check for recursion */ + if (conn->in_error_handler) { + DEBUG_TRACE( + "Recursion when handling error %u - fall back to default", + status); + } else { /* Send user defined error pages, if defined */ error_handler = conn->ctx->config[ERROR_PAGES]; error_page_file_ext = conn->ctx->config[INDEX_FILES]; page_handler_found = 0; + if (error_handler != NULL) { for (scope = 1; (scope <= 3) && !page_handler_found; scope++) { switch (scope) { @@ -2543,7 +4181,8 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...) error_handler, status); break; - case 2: /* Handler for error group, e.g., 5xx error handler + case 2: /* Handler for error group, e.g., 5xx error + * handler * for all server errors (500-599) */ mg_snprintf(conn, &truncated, @@ -2563,9 +4202,9 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...) break; } - /* String truncation in buf may only occur if error_handler - * is too long. This string is from the config, not from a - * client. */ + /* String truncation in buf may only occur if + * error_handler is too long. This string is + * from the config, not from a client. */ (void)truncated; len = (int)strlen(buf); @@ -2573,14 +4212,19 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...) tstr = strchr(error_page_file_ext, '.'); while (tstr) { - for (i = 1; i < 32 && tstr[i] != 0 && tstr[i] != ','; + for (i = 1; + (i < 32) && (tstr[i] != 0) && (tstr[i] != ','); i++) buf[len + i - 1] = tstr[i]; buf[len + i - 1] = 0; - if (mg_stat(conn, buf, &error_page_file)) { + + if (mg_stat(conn, buf, &error_page_file.stat)) { + DEBUG_TRACE("Check error page %s - found", buf); page_handler_found = 1; break; } + DEBUG_TRACE("Check error page %s - not found", buf); + tstr = strchr(tstr + i, '.'); } } @@ -2597,17 +4241,25 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...) /* No custom error page. Send default error page. */ gmt_time_string(date, sizeof(date), &curtime); + /* Errors 1xx, 204 and 304 MUST NOT send a body */ + has_body = ((status > 199) && (status != 204) && (status != 304)); + conn->must_close = 1; mg_printf(conn, "HTTP/1.1 %d %s\r\n", status, status_text); send_no_cache_header(conn); + send_additional_header(conn); + if (has_body) { + mg_printf(conn, + "%s", + "Content-Type: text/plain; charset=utf-8\r\n"); + } mg_printf(conn, "Date: %s\r\n" "Connection: close\r\n\r\n", date); /* Errors 1xx, 204 and 304 MUST NOT send a body */ - if (status > 199 && status != 204 && status != 304) { - + if (has_body) { mg_printf(conn, "Error %d: %s\n", status, status_text); if (fmt != NULL) { @@ -2635,30 +4287,34 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...) #endif +FUNCTION_MAY_BE_UNUSED static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) { (void)unused; *mutex = CreateMutex(NULL, FALSE, NULL); - return *mutex == NULL ? -1 : 0; + return (*mutex == NULL) ? -1 : 0; } - +FUNCTION_MAY_BE_UNUSED static int pthread_mutex_destroy(pthread_mutex_t *mutex) { - return CloseHandle(*mutex) == 0 ? -1 : 0; + return (CloseHandle(*mutex) == 0) ? -1 : 0; } +FUNCTION_MAY_BE_UNUSED static int pthread_mutex_lock(pthread_mutex_t *mutex) { - return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0 ? 0 : -1; + return (WaitForSingleObject(*mutex, (DWORD)INFINITE) == WAIT_OBJECT_0) ? 0 + : -1; } #ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS +FUNCTION_MAY_BE_UNUSED static int pthread_mutex_trylock(pthread_mutex_t *mutex) { @@ -2673,88 +4329,48 @@ pthread_mutex_trylock(pthread_mutex_t *mutex) #endif +FUNCTION_MAY_BE_UNUSED static int pthread_mutex_unlock(pthread_mutex_t *mutex) { - return ReleaseMutex(*mutex) == 0 ? -1 : 0; + return (ReleaseMutex(*mutex) == 0) ? -1 : 0; } -#ifndef WIN_PTHREADS_TIME_H -static int -clock_gettime(clockid_t clk_id, struct timespec *tp) -{ - FILETIME ft; - ULARGE_INTEGER li; - BOOL ok = FALSE; - double d; - static double perfcnt_per_sec = 0.0; - - if (tp) { - memset(tp, 0, sizeof(*tp)); - if (clk_id == CLOCK_REALTIME) { - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */ - tp->tv_sec = (time_t)(li.QuadPart / 10000000); - tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; - ok = TRUE; - } else if (clk_id == CLOCK_MONOTONIC) { - if (perfcnt_per_sec == 0.0) { - QueryPerformanceFrequency((LARGE_INTEGER *)&li); - perfcnt_per_sec = 1.0 / li.QuadPart; - } - if (perfcnt_per_sec != 0.0) { - QueryPerformanceCounter((LARGE_INTEGER *)&li); - d = li.QuadPart * perfcnt_per_sec; - tp->tv_sec = (time_t)d; - d -= tp->tv_sec; - tp->tv_nsec = (long)(d * 1.0E9); - ok = TRUE; - } - } - } - - return ok ? 0 : -1; -} -#endif - - +FUNCTION_MAY_BE_UNUSED static int pthread_cond_init(pthread_cond_t *cv, const void *unused) { (void)unused; InitializeCriticalSection(&cv->threadIdSec); - cv->waitingthreadcount = 0; - cv->waitingthreadhdls = - (pthread_t *)mg_calloc(MAX_WORKER_THREADS, sizeof(pthread_t)); - return (cv->waitingthreadhdls != NULL) ? 0 : -1; + cv->waiting_thread = NULL; + return 0; } +FUNCTION_MAY_BE_UNUSED static int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec *abstime) { - struct mg_workerTLS *tls = - (struct mg_workerTLS *)pthread_getspecific(sTlsKey); + struct mg_workerTLS **ptls, + *tls = (struct mg_workerTLS *)pthread_getspecific(sTlsKey); int ok; - struct timespec tsnow; int64_t nsnow, nswaitabs, nswaitrel; DWORD mswaitrel; EnterCriticalSection(&cv->threadIdSec); - assert(cv->waitingthreadcount < MAX_WORKER_THREADS); - cv->waitingthreadhdls[cv->waitingthreadcount] = - tls->pthread_cond_helper_mutex; - cv->waitingthreadcount++; + /* Add this thread to cv's waiting list */ + ptls = &cv->waiting_thread; + for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) + ; + tls->next_waiting_thread = NULL; + *ptls = tls; LeaveCriticalSection(&cv->threadIdSec); if (abstime) { - clock_gettime(CLOCK_REALTIME, &tsnow); - nsnow = (((int64_t)tsnow.tv_sec) * 1000000000) + tsnow.tv_nsec; + nsnow = mg_get_current_time_ns(); nswaitabs = (((int64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec; nswaitrel = nswaitabs - nsnow; @@ -2763,18 +4379,37 @@ pthread_cond_timedwait(pthread_cond_t *cv, } mswaitrel = (DWORD)(nswaitrel / 1000000); } else { - mswaitrel = INFINITE; + mswaitrel = (DWORD)INFINITE; } pthread_mutex_unlock(mutex); ok = (WAIT_OBJECT_0 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel)); + if (!ok) { + ok = 1; + EnterCriticalSection(&cv->threadIdSec); + ptls = &cv->waiting_thread; + for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) { + if (*ptls == tls) { + *ptls = tls->next_waiting_thread; + ok = 0; + break; + } + } + LeaveCriticalSection(&cv->threadIdSec); + if (ok) { + WaitForSingleObject(tls->pthread_cond_helper_mutex, + (DWORD)INFINITE); + } + } + /* This thread has been removed from cv's waiting list */ pthread_mutex_lock(mutex); return ok ? 0 : -1; } +FUNCTION_MAY_BE_UNUSED static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) { @@ -2782,23 +4417,19 @@ pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) } +FUNCTION_MAY_BE_UNUSED static int pthread_cond_signal(pthread_cond_t *cv) { - int i; HANDLE wkup = NULL; BOOL ok = FALSE; EnterCriticalSection(&cv->threadIdSec); - if (cv->waitingthreadcount) { - wkup = cv->waitingthreadhdls[0]; + if (cv->waiting_thread) { + wkup = cv->waiting_thread->pthread_cond_helper_mutex; + cv->waiting_thread = cv->waiting_thread->next_waiting_thread; + ok = SetEvent(wkup); - - for (i = 1; i < cv->waitingthreadcount; i++) { - cv->waitingthreadhdls[i - 1] = cv->waitingthreadhdls[i]; - } - cv->waitingthreadcount--; - assert(ok); } LeaveCriticalSection(&cv->threadIdSec); @@ -2807,11 +4438,12 @@ pthread_cond_signal(pthread_cond_t *cv) } +FUNCTION_MAY_BE_UNUSED static int pthread_cond_broadcast(pthread_cond_t *cv) { EnterCriticalSection(&cv->threadIdSec); - while (cv->waitingthreadcount) { + while (cv->waiting_thread) { pthread_cond_signal(cv); } LeaveCriticalSection(&cv->threadIdSec); @@ -2820,13 +4452,12 @@ pthread_cond_broadcast(pthread_cond_t *cv) } +FUNCTION_MAY_BE_UNUSED static int pthread_cond_destroy(pthread_cond_t *cv) { EnterCriticalSection(&cv->threadIdSec); - assert(cv->waitingthreadcount == 0); - mg_free(cv->waitingthreadhdls); - cv->waitingthreadhdls = 0; + assert(cv->waiting_thread == NULL); LeaveCriticalSection(&cv->threadIdSec); DeleteCriticalSection(&cv->threadIdSec); @@ -2834,6 +4465,41 @@ pthread_cond_destroy(pthread_cond_t *cv) } +#ifdef ALTERNATIVE_QUEUE +FUNCTION_MAY_BE_UNUSED +static void * +event_create(void) +{ + return (void *)CreateEvent(NULL, FALSE, FALSE, NULL); +} + + +FUNCTION_MAY_BE_UNUSED +static int +event_wait(void *eventhdl) +{ + int res = WaitForSingleObject((HANDLE)eventhdl, (DWORD)INFINITE); + return (res == WAIT_OBJECT_0); +} + + +FUNCTION_MAY_BE_UNUSED +static int +event_signal(void *eventhdl) +{ + return (int)SetEvent((HANDLE)eventhdl); +} + + +FUNCTION_MAY_BE_UNUSED +static void +event_destroy(void *eventhdl) +{ + CloseHandle((HANDLE)eventhdl); +} +#endif + + #if defined(__MINGW32__) /* Enable unused function warning again */ #pragma GCC diagnostic pop @@ -2854,7 +4520,7 @@ change_slashes_to_backslashes(char *path) /* remove double backslash (check i > 0 to preserve UNC paths, * like \\server\file.txt) */ if ((path[i] == '\\') && (i > 0)) { - while (path[i + 1] == '\\' || path[i + 1] == '/') { + while ((path[i + 1] == '\\') || (path[i + 1] == '/')) { (void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1)); } } @@ -2871,7 +4537,7 @@ mg_wcscasecmp(const wchar_t *s1, const wchar_t *s2) diff = tolower(*s1) - tolower(*s2); s1++; s2++; - } while (diff == 0 && s1[-1] != '\0'); + } while ((diff == 0) && (s1[-1] != '\0')); return diff; } @@ -2903,17 +4569,25 @@ path_to_unicode(const struct mg_connection *conn, wbuf[0] = L'\0'; } - /* TODO: Add a configuration to switch between case sensitive and - * case insensitive URIs for Windows server. */ - /* + /* Windows file systems are not case sensitive, but you can still use + * uppercase and lowercase letters (on all modern file systems). + * The server can check if the URI uses the same upper/lowercase + * letters an the file system, effectively making Windows servers + * case sensitive (like Linux servers are). It is still not possible + * to use two files with the same name in different cases on Windows + * (like /a and /A) - this would be possible in Linux. + * As a default, Windows is not case sensitive, but the case sensitive + * file name check can be activated by an additional configuration. */ if (conn) { - if (conn->ctx->config[WINDOWS_CASE_SENSITIVE]) { - fcompare = wcscmp; - } + if (conn->ctx->config[CASE_SENSITIVE_FILES] + && !mg_strcasecmp(conn->ctx->config[CASE_SENSITIVE_FILES], "yes")) { + /* Use case sensitive compare function */ + fcompare = wcscmp; + } } - */ (void)conn; /* conn is currently unused */ +#if !defined(_WIN32_WCE) /* Only accept a full file path, not a Windows short (8.3) path. */ memset(wbuf2, 0, ARRAY_SIZE(wbuf2) * sizeof(wchar_t)); long_len = GetLongPathNameW(wbuf, wbuf2, ARRAY_SIZE(wbuf2) - 1); @@ -2928,90 +4602,16 @@ path_to_unicode(const struct mg_connection *conn, /* Short name is used. */ wbuf[0] = L'\0'; } -} +#else + (void)long_len; + (void)wbuf2; + (void)err; - -#if defined(_WIN32_WCE) -/* Create substitutes for POSIX functions in Win32. */ - -#if defined(__MINGW32__) -/* Show no warning in case system functions are not used. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#endif - - -static time_t -time(time_t *ptime) -{ - time_t t; - SYSTEMTIME st; - FILETIME ft; - - GetSystemTime(&st); - SystemTimeToFileTime(&st, &ft); - t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime); - - if (ptime != NULL) { - *ptime = t; + if (strchr(path, '~')) { + wbuf[0] = L'\0'; } - - return t; -} - - -static struct tm * -localtime(const time_t *ptime, struct tm *ptm) -{ - int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF; - FILETIME ft, lft; - SYSTEMTIME st; - TIME_ZONE_INFORMATION tzinfo; - - if (ptm == NULL) { - return NULL; - } - - *(int64_t *)&ft = t; - FileTimeToLocalFileTime(&ft, &lft); - FileTimeToSystemTime(&lft, &st); - ptm->tm_year = st.wYear - 1900; - ptm->tm_mon = st.wMonth - 1; - ptm->tm_wday = st.wDayOfWeek; - ptm->tm_mday = st.wDay; - ptm->tm_hour = st.wHour; - ptm->tm_min = st.wMinute; - ptm->tm_sec = st.wSecond; - ptm->tm_yday = 0; /* hope nobody uses this */ - ptm->tm_isdst = - GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0; - - return ptm; -} - - -static struct tm * -gmtime(const time_t *ptime, struct tm *ptm) -{ - /* FIXME(lsm): fix this. */ - return localtime(ptime, ptm); -} - - -static size_t -strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm) -{ - (void)mg_snprintf(NULL, dst, dst_size, "implement strftime() for WinCE"); - return 0; -} - - -#if defined(__MINGW32__) -/* Enable unused function warning again */ -#pragma GCC diagnostic pop -#endif - #endif +} /* Windows happily opens files with some garbage at the end of file name. @@ -3028,7 +4628,9 @@ path_cannot_disclose_cgi(const char *path) static int -mg_stat(struct mg_connection *conn, const char *path, struct file *filep) +mg_stat(const struct mg_connection *conn, + const char *path, + struct mg_file_stat *filep) { wchar_t wbuf[PATH_MAX]; WIN32_FILE_ATTRIBUTE_DATA info; @@ -3039,14 +4641,30 @@ mg_stat(struct mg_connection *conn, const char *path, struct file *filep) } memset(filep, 0, sizeof(*filep)); - if (conn && is_file_in_memory(conn, path, filep)) { + if (conn && is_file_in_memory(conn, path)) { /* filep->is_directory = 0; filep->gzipped = 0; .. already done by * memset */ - filep->last_modified = time(NULL); - /* last_modified = now ... assumes the file may change during runtime, + + /* Quick fix (for 1.9.x): */ + /* mg_stat must fill all fields, also for files in memory */ + struct mg_file tmp_file = STRUCT_FILE_INITIALIZER; + open_file_in_memory(conn, path, &tmp_file, MG_FOPEN_MODE_NONE); + filep->size = tmp_file.stat.size; + filep->location = 2; + /* TODO: for 1.10: restructure how files in memory are handled */ + + /* The "file in memory" feature is a candidate for deletion. + * Please join the discussion at + * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI + */ + + filep->last_modified = time(NULL); /* TODO */ + /* last_modified = now ... assumes the file may change during + * runtime, * so every mg_fopen call may return different data */ /* last_modified = conn->ctx.start_time; - * May be used it the data does not change during runtime. This allows + * May be used it the data does not change during runtime. This + * allows * browser caching. Since we do not know, we have to assume the file * in memory may change. */ return 1; @@ -3115,6 +4733,7 @@ mg_mkdir(const struct mg_connection *conn, const char *path, int mode) /* Implementation of POSIX opendir/closedir/readdir for Windows. */ +FUNCTION_MAY_BE_UNUSED static DIR * mg_opendir(const struct mg_connection *conn, const char *name) { @@ -3144,6 +4763,7 @@ mg_opendir(const struct mg_connection *conn, const char *name) } +FUNCTION_MAY_BE_UNUSED static int mg_closedir(DIR *dir) { @@ -3163,6 +4783,7 @@ mg_closedir(DIR *dir) } +FUNCTION_MAY_BE_UNUSED static struct dirent * mg_readdir(DIR *dir) { @@ -3197,6 +4818,7 @@ mg_readdir(DIR *dir) #ifndef HAVE_POLL +FUNCTION_MAY_BE_UNUSED static int poll(struct pollfd *pfd, unsigned int n, int milliseconds) { @@ -3228,10 +4850,18 @@ poll(struct pollfd *pfd, unsigned int n, int milliseconds) } } + /* We should subtract the time used in select from remaining + * "milliseconds", in particular if called from mg_poll with a + * timeout quantum. + * Unfortunately, the remaining time is not stored in "tv" in all + * implementations, so the result in "tv" must be considered undefined. + * See http://man7.org/linux/man-pages/man2/select.2.html */ + return result; } #endif /* HAVE_POLL */ + #if defined(__MINGW32__) /* Enable unused function warning again */ #pragma GCC diagnostic pop @@ -3242,7 +4872,11 @@ static void set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */) { (void)conn; /* Unused. */ +#if defined(_WIN32_WCE) + (void)sock; +#else (void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0); +#endif } @@ -3250,7 +4884,8 @@ int mg_start_thread(mg_thread_func_t f, void *p) { #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) - /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384 + /* Compile-time option to control stack size, e.g. + * -DUSE_STACK_SIZE=16384 */ return ((_beginthread((void(__cdecl *)(void *))f, USE_STACK_SIZE, p) == ((uintptr_t)(-1L))) @@ -3294,7 +4929,7 @@ mg_join_thread(pthread_t threadid) DWORD dwevent; result = -1; - dwevent = WaitForSingleObject(threadid, INFINITE); + dwevent = WaitForSingleObject(threadid, (DWORD)INFINITE); if (dwevent == WAIT_FAILED) { DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO); } else { @@ -3307,7 +4942,8 @@ mg_join_thread(pthread_t threadid) return result; } -#if !defined(NO_SSL_DL) +#if !defined(NO_SSL_DL) && !defined(NO_SSL) +/* If SSL is loaded dynamically, dlopen/dlclose is required. */ /* Create substitutes for POSIX functions in Win32. */ #if defined(__MINGW32__) @@ -3317,6 +4953,7 @@ mg_join_thread(pthread_t threadid) #endif +FUNCTION_MAY_BE_UNUSED static HANDLE dlopen(const char *dll_name, int flags) { @@ -3327,6 +4964,7 @@ dlopen(const char *dll_name, int flags) } +FUNCTION_MAY_BE_UNUSED static int dlclose(void *handle) { @@ -3366,7 +5004,7 @@ static void trim_trailing_whitespaces(char *s) { char *e = s + strlen(s) - 1; - while (e > s && isspace(*(unsigned char *)e)) { + while ((e > s) && isspace(*(unsigned char *)e)) { *e-- = '\0'; } } @@ -3386,7 +5024,7 @@ spawn_process(struct mg_connection *conn, char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX], cmdline[PATH_MAX], buf[PATH_MAX]; int truncated; - struct file file = STRUCT_FILE_INITIALIZER; + struct mg_file file = STRUCT_FILE_INITIALIZER; STARTUPINFOA si; PROCESS_INFORMATION pi = {0}; @@ -3448,14 +5086,14 @@ spawn_process(struct mg_connection *conn, goto spawn_cleanup; } - if (mg_fopen(conn, cmdline, "r", &file)) { - p = (char *)file.membuf; + if (mg_fopen(conn, cmdline, MG_FOPEN_MODE_READ, &file)) { + p = (char *)file.access.membuf; mg_fgets(buf, sizeof(buf), &file, &p); - mg_fclose(&file); + (void)mg_fclose(&file.access); /* ignore error on read only file */ buf[sizeof(buf) - 1] = '\0'; } - if (buf[0] == '#' && buf[1] == '!') { + if ((buf[0] == '#') && (buf[1] == '!')) { trim_trailing_whitespaces(buf + 2); } else { buf[2] = '\0'; @@ -3524,16 +5162,24 @@ spawn_cleanup: static int -set_non_blocking_mode(SOCKET sock) +set_blocking_mode(SOCKET sock) { - unsigned long on = 1; - return ioctlsocket(sock, (long)FIONBIO, &on); + unsigned long non_blocking = 0; + return ioctlsocket(sock, (long)FIONBIO, &non_blocking); } +static int +set_non_blocking_mode(SOCKET sock) +{ + unsigned long non_blocking = 1; + return ioctlsocket(sock, (long)FIONBIO, &non_blocking); +} #else static int -mg_stat(struct mg_connection *conn, const char *path, struct file *filep) +mg_stat(const struct mg_connection *conn, + const char *path, + struct mg_file_stat *filep) { struct stat st; if (!filep) { @@ -3541,7 +5187,17 @@ mg_stat(struct mg_connection *conn, const char *path, struct file *filep) } memset(filep, 0, sizeof(*filep)); - if (conn && is_file_in_memory(conn, path, filep)) { + if (conn && is_file_in_memory(conn, path)) { + + /* Quick fix (for 1.9.x): */ + /* mg_stat must fill all fields, also for files in memory */ + struct mg_file tmp_file = STRUCT_FILE_INITIALIZER; + open_file_in_memory(conn, path, &tmp_file, MG_FOPEN_MODE_NONE); + filep->size = tmp_file.stat.size; + filep->last_modified = time(NULL); + filep->location = 2; + /* TODO: for 1.10: restructure how files in memory are handled */ + return 1; } @@ -3653,10 +5309,10 @@ spawn_process(struct mg_connection *conn, if ((pid = fork()) == -1) { /* Parent */ - send_http_error(conn, - 500, - "Error: Creating CGI process\nfork(): %s", - strerror(ERRNO)); + mg_send_http_error(conn, + 500, + "Error: Creating CGI process\nfork(): %s", + strerror(ERRNO)); } else if (pid == 0) { /* Child */ if (chdir(dir) != 0) { @@ -3728,14 +5384,32 @@ spawn_process(struct mg_connection *conn, static int set_non_blocking_mode(SOCKET sock) { - int flags; - - flags = fcntl(sock, F_GETFL, 0); - (void)fcntl(sock, F_SETFL, flags | O_NONBLOCK); + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + return -1; + } + if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) < 0) { + return -1; + } return 0; } -#endif /* _WIN32 */ + +static int +set_blocking_mode(SOCKET sock) +{ + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + return -1; + } + + if (fcntl(sock, F_SETFL, flags & (~(int)(O_NONBLOCK))) < 0) { + return -1; + } + return 0; +} +#endif /* _WIN32 / else */ + /* End of initial operating system specific define block. */ @@ -3745,46 +5419,91 @@ get_random(void) { static uint64_t lfsr = 0; /* Linear feedback shift register */ static uint64_t lcg = 0; /* Linear congruential generator */ - struct timespec now; - - memset(&now, 0, sizeof(now)); - clock_gettime(CLOCK_MONOTONIC, &now); + uint64_t now = mg_get_current_time_ns(); if (lfsr == 0) { /* lfsr will be only 0 if has not been initialized, * so this code is called only once. */ - lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec) - ^ ((uint64_t)(ptrdiff_t)&now) ^ (((uint64_t)time(NULL)) << 33); - lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec - + (uint64_t)(ptrdiff_t)&now; + lfsr = mg_get_current_time_ns(); + lcg = mg_get_current_time_ns(); } else { /* Get the next step of both random number generators. */ lfsr = (lfsr >> 1) | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1) << 63); - lcg = lcg * 6364136223846793005 + 1442695040888963407; + lcg = lcg * 6364136223846793005LL + 1442695040888963407LL; } - /* Combining two pseudo-random number generators and a high resolution part - * of the current server time will make it hard (impossible?) to guess the + /* Combining two pseudo-random number generators and a high resolution + * part + * of the current server time will make it hard (impossible?) to guess + * the * next number. */ - return (lfsr ^ lcg ^ (uint64_t)now.tv_nsec); + return (lfsr ^ lcg ^ now); +} + + +static int +mg_poll(struct pollfd *pfd, + unsigned int n, + int milliseconds, + volatile int *stop_server) +{ + /* Call poll, but only for a maximum time of a few seconds. + * This will allow to stop the server after some seconds, instead + * of having to wait for a long socket timeout. */ + int ms_now = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */ + + do { + int result; + + if (*stop_server) { + /* Shut down signal */ + return -2; + } + + if ((milliseconds >= 0) && (milliseconds < ms_now)) { + ms_now = milliseconds; + } + + result = poll(pfd, n, ms_now); + if (result != 0) { + /* Poll returned either success (1) or error (-1). + * Forward both to the caller. */ + return result; + } + + /* Poll returned timeout (0). */ + if (milliseconds > 0) { + milliseconds -= ms_now; + } + + } while (milliseconds != 0); + + /* timeout: return 0 */ + return 0; } /* Write data to the IO channel - opened file descriptor, socket or SSL - * descriptor. Return number of bytes written. */ + * descriptor. + * Return value: + * >=0 .. number of bytes successfully written + * -1 .. timeout + * -2 .. error + */ static int -push(struct mg_context *ctx, - FILE *fp, - SOCKET sock, - SSL *ssl, - const char *buf, - int len, - double timeout) +push_inner(struct mg_context *ctx, + FILE *fp, + SOCKET sock, + SSL *ssl, + const char *buf, + int len, + double timeout) { - struct timespec start, now; + uint64_t start = 0, now = 0, timeout_ns = 0; int n, err; + unsigned ms_wait = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */ #ifdef _WIN32 typedef int len_t; @@ -3793,33 +5512,38 @@ push(struct mg_context *ctx, #endif if (timeout > 0) { - memset(&start, 0, sizeof(start)); - memset(&now, 0, sizeof(now)); - clock_gettime(CLOCK_MONOTONIC, &start); + now = mg_get_current_time_ns(); + start = now; + timeout_ns = (uint64_t)(timeout * 1.0E9); } if (ctx == NULL) { - return -1; + return -2; } #ifdef NO_SSL if (ssl) { - return -1; + return -2; } #endif - do { + /* Try to read until it succeeds, fails, times out, or the server + * shuts down. */ + for (;;) { #ifndef NO_SSL if (ssl != NULL) { n = SSL_write(ssl, buf, len); if (n <= 0) { err = SSL_get_error(ssl, n); - if ((err == 5 /* SSL_ERROR_SYSCALL */) && (n == -1)) { + if ((err == SSL_ERROR_SYSCALL) && (n == -1)) { err = ERRNO; + } else if ((err == SSL_ERROR_WANT_READ) + || (err == SSL_ERROR_WANT_WRITE)) { + n = 0; } else { DEBUG_TRACE("SSL_write() failed, error %d", err); - return -1; + return -2; } } else { err = 0; @@ -3837,38 +5561,75 @@ push(struct mg_context *ctx, } else { n = (int)send(sock, buf, (len_t)len, MSG_NOSIGNAL); err = (n < 0) ? ERRNO : 0; +#ifdef _WIN32 + if (err == WSAEWOULDBLOCK) { + err = 0; + n = 0; + } +#else + if (err == EWOULDBLOCK) { + err = 0; + n = 0; + } +#endif + if (n < 0) { + /* shutdown of the socket at client side */ + return -2; + } } if (ctx->stop_flag) { - return -1; + return -2; } - if ((n > 0) || (n == 0 && len == 0)) { + if ((n > 0) || ((n == 0) && (len == 0))) { /* some data has been read, or no data was requested */ return n; } - if (n == 0) { - /* shutdown of the socket at client side */ - return -1; - } if (n < 0) { /* socket error - check errno */ DEBUG_TRACE("send() failed, error %d", err); - /* TODO: error handling depending on the error code. + /* TODO (mid): error handling depending on the error code. * These codes are different between Windows and Linux. + * Currently there is no problem with failing send calls, + * if there is a reproducible situation, it should be + * investigated in detail. */ - return -1; + return -2; } - /* This code is not reached in the moment. - * ==> Fix the TODOs above first. */ + /* Only in case n=0 (timeout), repeat calling the write function */ + + /* If send failed, wait before retry */ + if (fp != NULL) { + /* For files, just wait a fixed time, + * maybe an average disk seek time. */ + mg_sleep(ms_wait > 10 ? 10 : ms_wait); + } else { + /* For sockets, wait for the socket using poll */ + struct pollfd pfd[1]; + int pollres; + + pfd[0].fd = sock; + pfd[0].events = POLLOUT; + pollres = mg_poll(pfd, 1, (int)(ms_wait), &(ctx->stop_flag)); + if (ctx->stop_flag) { + return -2; + } + if (pollres > 0) { + continue; + } + } if (timeout > 0) { - clock_gettime(CLOCK_MONOTONIC, &now); + now = mg_get_current_time_ns(); + if ((now - start) > timeout_ns) { + /* Timeout */ + break; + } } - - } while ((timeout <= 0) || (mg_difftimespec(&now, &start) <= timeout)); + } (void)err; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not used */ @@ -3896,8 +5657,8 @@ push_all(struct mg_context *ctx, timeout = atoi(ctx->config[REQUEST_TIMEOUT]) / 1000.0; } - while (len > 0 && ctx->stop_flag == 0) { - n = push(ctx, fp, sock, ssl, buf + nwritten, (int)len, timeout); + while ((len > 0) && (ctx->stop_flag == 0)) { + n = push_inner(ctx, fp, sock, ssl, buf + nwritten, (int)len, timeout); if (n < 0) { if (nwritten == 0) { nwritten = n; /* Propagate the error */ @@ -3916,106 +5677,192 @@ push_all(struct mg_context *ctx, /* Read from IO channel - opened file descriptor, socket, or SSL descriptor. - * Return negative value on error, or number of bytes read on success. */ + * Return value: + * >=0 .. number of bytes successfully read + * -1 .. timeout + * -2 .. error + */ static int -pull(FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout) +pull_inner(FILE *fp, + struct mg_connection *conn, + char *buf, + int len, + double timeout) { - int nread, err; - struct timespec start, now; + int nread, err = 0; #ifdef _WIN32 typedef int len_t; #else typedef size_t len_t; #endif +#ifndef NO_SSL + int ssl_pending; +#endif - if (timeout > 0) { - memset(&start, 0, sizeof(start)); - memset(&now, 0, sizeof(now)); - clock_gettime(CLOCK_MONOTONIC, &start); - } + /* We need an additional wait loop around this, because in some cases + * with TLSwe may get data from the socket but not from SSL_read. + * In this case we need to repeat at least once. + */ - do { - if (fp != NULL) { - /* Use read() instead of fread(), because if we're reading from the - * CGI pipe, fread() may block until IO buffer is filled up. We - * cannot afford to block and must pass all read bytes immediately - * to the client. */ - nread = (int)read(fileno(fp), buf, (size_t)len); - err = (nread < 0) ? ERRNO : 0; + if (fp != NULL) { +#if !defined(_WIN32_WCE) + /* Use read() instead of fread(), because if we're reading from the + * CGI pipe, fread() may block until IO buffer is filled up. We + * cannot afford to block and must pass all read bytes immediately + * to the client. */ + nread = (int)read(fileno(fp), buf, (size_t)len); +#else + /* WinCE does not support CGI pipes */ + nread = (int)fread(buf, 1, (size_t)len, fp); +#endif + err = (nread < 0) ? ERRNO : 0; + if ((nread == 0) && (len > 0)) { + /* Should get data, but got EOL */ + return -2; + } #ifndef NO_SSL - } else if (conn->ssl != NULL) { + } else if ((conn->ssl != NULL) + && ((ssl_pending = SSL_pending(conn->ssl)) > 0)) { + /* We already know there is no more data buffered in conn->buf + * but there is more available in the SSL layer. So don't poll + * conn->client.sock yet. */ + if (ssl_pending > len) { + ssl_pending = len; + } + nread = SSL_read(conn->ssl, buf, ssl_pending); + if (nread <= 0) { + err = SSL_get_error(conn->ssl, nread); + if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) { + err = ERRNO; + } else if ((err == SSL_ERROR_WANT_READ) + || (err == SSL_ERROR_WANT_WRITE)) { + nread = 0; + } else { + DEBUG_TRACE("SSL_read() failed, error %d", err); + return -1; + } + } else { + err = 0; + } + + } else if (conn->ssl != NULL) { + + struct pollfd pfd[1]; + int pollres; + + pfd[0].fd = conn->client.sock; + pfd[0].events = POLLIN; + pollres = + mg_poll(pfd, 1, (int)(timeout * 1000.0), &(conn->ctx->stop_flag)); + if (conn->ctx->stop_flag) { + return -2; + } + if (pollres > 0) { nread = SSL_read(conn->ssl, buf, len); if (nread <= 0) { err = SSL_get_error(conn->ssl, nread); - if ((err == 5 /* SSL_ERROR_SYSCALL */) && (nread == -1)) { + if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) { err = ERRNO; + } else if ((err == SSL_ERROR_WANT_READ) + || (err == SSL_ERROR_WANT_WRITE)) { + nread = 0; } else { DEBUG_TRACE("SSL_read() failed, error %d", err); - return -1; + return -2; } } else { err = 0; } + + } else if (pollres < 0) { + /* Error */ + return -2; + } else { + /* pollres = 0 means timeout */ + nread = 0; + } #endif - } else { + } else { + struct pollfd pfd[1]; + int pollres; + + pfd[0].fd = conn->client.sock; + pfd[0].events = POLLIN; + pollres = + mg_poll(pfd, 1, (int)(timeout * 1000.0), &(conn->ctx->stop_flag)); + if (conn->ctx->stop_flag) { + return -2; + } + if (pollres > 0) { nread = (int)recv(conn->client.sock, buf, (len_t)len, 0); err = (nread < 0) ? ERRNO : 0; + if (nread <= 0) { + /* shutdown of the socket at client side */ + return -2; + } + } else if (pollres < 0) { + /* error callint poll */ + return -2; + } else { + /* pollres = 0 means timeout */ + nread = 0; } + } - if (conn->ctx->stop_flag) { - return -1; - } + if (conn->ctx->stop_flag) { + return -2; + } - if ((nread > 0) || (nread == 0 && len == 0)) { - /* some data has been read, or no data was requested */ - return nread; - } - if (nread == 0) { - /* shutdown of the socket at client side */ - return -1; - } - if (nread < 0) { + if ((nread > 0) || ((nread == 0) && (len == 0))) { + /* some data has been read, or no data was requested */ + return nread; + } + + if (nread < 0) { /* socket error - check errno */ #ifdef _WIN32 - if (err == WSAEWOULDBLOCK) { - /* standard case if called from close_socket_gracefully */ - return -1; - } else if (err == WSAETIMEDOUT) { - /* timeout is handled by the while loop */ - } else { - DEBUG_TRACE("recv() failed, error %d", err); - return -1; - } + if (err == WSAEWOULDBLOCK) { + /* TODO (low): check if this is still required */ + /* standard case if called from close_socket_gracefully */ + return -2; + } else if (err == WSAETIMEDOUT) { + /* TODO (low): check if this is still required */ + /* timeout is handled by the while loop */ + return 0; + } else if (err == WSAECONNABORTED) { + /* See https://www.chilkatsoft.com/p/p_299.asp */ + return -2; + } else { + DEBUG_TRACE("recv() failed, error %d", err); + return -2; + } #else - /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases, - * if the timeout is reached and if the socket was set to non- - * blocking in close_socket_gracefully, so we can not distinguish - * here. We have to wait for the timeout in both cases for now. - */ - if (err == EAGAIN || err == EWOULDBLOCK || err == EINTR) { - /* EAGAIN/EWOULDBLOCK: - * standard case if called from close_socket_gracefully - * => should return -1 */ - /* or timeout occured - * => the code must stay in the while loop */ + /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases, + * if the timeout is reached and if the socket was set to non- + * blocking in close_socket_gracefully, so we can not distinguish + * here. We have to wait for the timeout in both cases for now. + */ + if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == EINTR)) { + /* TODO (low): check if this is still required */ + /* EAGAIN/EWOULDBLOCK: + * standard case if called from close_socket_gracefully + * => should return -1 */ + /* or timeout occured + * => the code must stay in the while loop */ - /* EINTR can be generated on a socket with a timeout set even - * when SA_RESTART is effective for all relevant signals - * (see signal(7)). - * => stay in the while loop */ - } else { - DEBUG_TRACE("recv() failed, error %d", err); - return -1; - } + /* EINTR can be generated on a socket with a timeout set even + * when SA_RESTART is effective for all relevant signals + * (see signal(7)). + * => stay in the while loop */ + } else { + DEBUG_TRACE("recv() failed, error %d", err); + return -2; + } #endif - } - if (timeout > 0) { - clock_gettime(CLOCK_MONOTONIC, &now); - } - } while ((timeout <= 0) || (mg_difftimespec(&now, &start) <= timeout)); + } /* Timeout occured, but no data available. */ return -1; @@ -4027,16 +5874,30 @@ pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) { int n, nread = 0; double timeout = -1.0; + uint64_t start_time = 0, now = 0, timeout_ns = 0; if (conn->ctx->config[REQUEST_TIMEOUT]) { timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0; } + if (timeout >= 0.0) { + start_time = mg_get_current_time_ns(); + timeout_ns = (uint64_t)(timeout * 1.0E9); + } - while (len > 0 && conn->ctx->stop_flag == 0) { - n = pull(fp, conn, buf + nread, len, timeout); - if (n < 0) { + while ((len > 0) && (conn->ctx->stop_flag == 0)) { + n = pull_inner(fp, conn, buf + nread, len, timeout); + if (n == -2) { if (nread == 0) { - nread = n; /* Propagate the error */ + nread = -1; /* Propagate the error */ + } + break; + } else if (n == -1) { + /* timeout */ + if (timeout >= 0.0) { + now = mg_get_current_time_ns(); + if ((now - start_time) <= timeout_ns) { + continue; + } } break; } else if (n == 0) { @@ -4066,9 +5927,9 @@ discard_unread_request_data(struct mg_connection *conn) to_read = sizeof(buf); if (conn->is_chunked) { - /* Chunked encoding: 1=chunk not read completely, 2=chunk read + /* Chunked encoding: 3=chunk read completely * completely */ - while (conn->is_chunked == 1) { + while (conn->is_chunked != 3) { nread = mg_read(conn, buf, to_read); if (nread <= 0) { break; @@ -4097,7 +5958,7 @@ mg_read_inner(struct mg_connection *conn, void *buf, size_t len) { int64_t n, buffered_len, nread; int64_t len64 = - (int64_t)(len > INT_MAX ? INT_MAX : len); /* since the return value is + (int64_t)((len > INT_MAX) ? INT_MAX : len); /* since the return value is * int, we may not read more * bytes */ const char *body; @@ -4106,11 +5967,19 @@ mg_read_inner(struct mg_connection *conn, void *buf, size_t len) return 0; } - /* If Content-Length is not set for a PUT or POST request, read until - * socket is closed */ - if (conn->consumed_content == 0 && conn->content_len == -1) { - conn->content_len = INT64_MAX; - conn->must_close = 1; + /* If Content-Length is not set for a request with body data + * (e.g., a PUT or POST request), we do not know in advance + * how much data should be read. */ + if (conn->consumed_content == 0) { + if (conn->is_chunked == 1) { + conn->content_len = len64; + conn->is_chunked = 2; + } else if (conn->content_len == -1) { + /* The body data is completed when the connection + * is closed. */ + conn->content_len = INT64_MAX; + conn->must_close = 1; + } } nread = 0; @@ -4118,7 +5987,8 @@ mg_read_inner(struct mg_connection *conn, void *buf, size_t len) /* Adjust number of bytes to read. */ int64_t left_to_read = conn->content_len - conn->consumed_content; if (left_to_read < len64) { - /* Do not read more than the total content length of the request. + /* Do not read more than the total content length of the + * request. */ len64 = left_to_read; } @@ -4144,7 +6014,7 @@ mg_read_inner(struct mg_connection *conn, void *buf, size_t len) if ((n = pull_all(NULL, conn, (char *)buf, (int)len64)) >= 0) { nread += n; } else { - nread = (nread > 0 ? nread : n); + nread = ((nread > 0) ? nread : n); } } return (int)nread; @@ -4158,7 +6028,6 @@ mg_getc(struct mg_connection *conn) if (conn == NULL) { return 0; } - conn->content_len++; if (mg_read_inner(conn, &c, 1) <= 0) { return (char)0; } @@ -4181,8 +6050,7 @@ mg_read(struct mg_connection *conn, void *buf, size_t len) size_t all_read = 0; while (len > 0) { - - if (conn->is_chunked == 2) { + if (conn->is_chunked == 3) { /* No more data left to read */ return 0; } @@ -4197,15 +6065,24 @@ mg_read(struct mg_connection *conn, void *buf, size_t len) conn->content_len += (int)read_now; read_ret = mg_read_inner(conn, (char *)buf + all_read, read_now); - all_read += (size_t)read_ret; - conn->chunk_remainder -= read_now; - len -= read_now; + if (read_ret < 1) { + /* read error */ + return -1; + } + + all_read += (size_t)read_ret; + conn->chunk_remainder -= (size_t)read_ret; + len -= (size_t)read_ret; if (conn->chunk_remainder == 0) { - /* the rest of the data in the current chunk has been read - */ - if ((mg_getc(conn) != '\r') || (mg_getc(conn) != '\n')) { + /* Add data bytes in the current chunk have been read, + * so we are expecting \r\n now. */ + char x1, x2; + conn->content_len += 2; + x1 = mg_getc(conn); + x2 = mg_getc(conn); + if ((x1 != '\r') || (x2 != '\n')) { /* Protocol violation */ return -1; } @@ -4219,20 +6096,23 @@ mg_read(struct mg_connection *conn, void *buf, size_t len) unsigned long chunkSize = 0; for (i = 0; i < ((int)sizeof(lenbuf) - 1); i++) { + conn->content_len++; lenbuf[i] = mg_getc(conn); - if (i > 0 && lenbuf[i] == '\r' && lenbuf[i - 1] != '\r') { + if ((i > 0) && (lenbuf[i] == '\r') + && (lenbuf[i - 1] != '\r')) { continue; } - if (i > 1 && lenbuf[i] == '\n' && lenbuf[i - 1] == '\r') { + if ((i > 1) && (lenbuf[i] == '\n') + && (lenbuf[i - 1] == '\r')) { lenbuf[i + 1] = 0; chunkSize = strtoul(lenbuf, &end, 16); if (chunkSize == 0) { /* regular end of content */ - conn->is_chunked = 2; + conn->is_chunked = 3; } break; } - if (!isalnum(lenbuf[i])) { + if (!isxdigit(lenbuf[i])) { /* illegal character for chunk length */ return -1; } @@ -4282,8 +6162,8 @@ mg_write(struct mg_connection *conn, const void *buf, size_t len) (int64_t)allowed)) == allowed) { buf = (const char *)buf + total; conn->last_throttle_bytes += total; - while (total < (int64_t)len && conn->ctx->stop_flag == 0) { - allowed = conn->throttle > (int64_t)len - total + while ((total < (int64_t)len) && (conn->ctx->stop_flag == 0)) { + allowed = (conn->throttle > ((int64_t)len - total)) ? (int64_t)len - total : conn->throttle; if ((n = push_all(conn->ctx, @@ -4309,10 +6189,51 @@ mg_write(struct mg_connection *conn, const void *buf, size_t len) (const char *)buf, (int64_t)len); } + if (total > 0) { + conn->num_bytes_sent += total; + } return (int)total; } +/* Send a chunk, if "Transfer-Encoding: chunked" is used */ +int +mg_send_chunk(struct mg_connection *conn, + const char *chunk, + unsigned int chunk_len) +{ + char lenbuf[16]; + size_t lenbuf_len; + int ret; + int t; + + /* First store the length information in a text buffer. */ + sprintf(lenbuf, "%x\r\n", chunk_len); + lenbuf_len = strlen(lenbuf); + + /* Then send length information, chunk and terminating \r\n. */ + ret = mg_write(conn, lenbuf, lenbuf_len); + if (ret != (int)lenbuf_len) { + return -1; + } + t = ret; + + ret = mg_write(conn, chunk, chunk_len); + if (ret != (int)chunk_len) { + return -1; + } + t += ret; + + ret = mg_write(conn, "\r\n", 2); + if (ret != 2) { + return -1; + } + t += ret; + + return t; +} + + /* Alternative alloc_vprintf() for non-compliant C runtimes */ static int alloc_vprintf2(char **buf, const char *fmt, va_list ap) @@ -4344,7 +6265,8 @@ alloc_vprintf2(char **buf, const char *fmt, va_list ap) /* Print message to buffer. If buffer is large enough to hold the message, - * return buffer. If buffer is to small, allocate large enough buffer on heap, + * return buffer. If buffer is to small, allocate large enough buffer on + * heap, * and return allocated buffer. */ static int alloc_vprintf(char **out_buf, @@ -4368,10 +6290,11 @@ alloc_vprintf(char **out_buf, if (len < 0) { /* C runtime is not standard compliant, vsnprintf() returned -1. - * Switch to alternative code path that uses incremental allocations. + * Switch to alternative code path that uses incremental + * allocations. */ va_copy(ap_copy, ap); - len = alloc_vprintf2(out_buf, fmt, ap); + len = alloc_vprintf2(out_buf, fmt, ap_copy); va_end(ap_copy); } else if ((size_t)(len) >= prealloc_size) { @@ -4412,7 +6335,7 @@ mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) { len = mg_write(conn, buf, (size_t)len); } - if (buf != mem && buf != NULL) { + if ((buf != mem) && (buf != NULL)) { mg_free(buf); } @@ -4442,17 +6365,17 @@ mg_url_decode(const char *src, int is_form_url_encoded) { int i, j, a, b; -#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') +#define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W')) - for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { - if (i < src_len - 2 && src[i] == '%' + for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) { + if ((i < src_len - 2) && (src[i] == '%') && isxdigit(*(const unsigned char *)(src + i + 1)) && isxdigit(*(const unsigned char *)(src + i + 2))) { a = tolower(*(const unsigned char *)(src + i + 1)); b = tolower(*(const unsigned char *)(src + i + 2)); dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b)); i += 2; - } else if (is_form_url_encoded && src[i] == '+') { + } else if (is_form_url_encoded && (src[i] == '+')) { dst[j] = ' '; } else { dst[j] = src[i]; @@ -4461,7 +6384,7 @@ mg_url_decode(const char *src, dst[j] = '\0'; /* Null-terminate the destination */ - return i >= src_len ? j : -1; + return (i >= src_len) ? j : -1; } @@ -4488,9 +6411,9 @@ mg_get_var2(const char *data, size_t name_len; int len; - if (dst == NULL || dst_len == 0) { + if ((dst == NULL) || (dst_len == 0)) { len = -2; - } else if (data == NULL || name == NULL || data_len == 0) { + } else if ((data == NULL) || (name == NULL) || (data_len == 0)) { len = -1; dst[0] = '\0'; } else { @@ -4501,7 +6424,7 @@ mg_get_var2(const char *data, /* data is "var1=val1&var2=val2...". Find variable first */ for (p = data; p + name_len < e; p++) { - if ((p == data || p[-1] == '&') && p[name_len] == '=' + if (((p == data) || (p[-1] == '&')) && (p[name_len] == '=') && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) { /* Point p to variable value */ p += name_len + 1; @@ -4533,6 +6456,7 @@ mg_get_var2(const char *data, } +/* HCP24: some changes to compare hole var_name */ int mg_get_cookie(const char *cookie_header, const char *var_name, @@ -4542,18 +6466,21 @@ mg_get_cookie(const char *cookie_header, const char *s, *p, *end; int name_len, len = -1; - if (dst == NULL || dst_size == 0) { - len = -2; - } else if (var_name == NULL || (s = cookie_header) == NULL) { - len = -1; - dst[0] = '\0'; - } else { - name_len = (int)strlen(var_name); - end = s + strlen(s); - dst[0] = '\0'; + if ((dst == NULL) || (dst_size == 0)) { + return -2; + } - for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) { - if (s[name_len] == '=') { + dst[0] = '\0'; + if ((var_name == NULL) || ((s = cookie_header) == NULL)) { + return -1; + } + + name_len = (int)strlen(var_name); + end = s + strlen(s); + for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) { + if (s[name_len] == '=') { + /* HCP24: now check is it a substring or a full cookie name */ + if ((s == cookie_header) || (s[-1] == ' ')) { s += name_len + 1; if ((p = strchr(s, ' ')) == NULL) { p = end; @@ -4561,7 +6488,7 @@ mg_get_cookie(const char *cookie_header, if (p[-1] == ';') { p--; } - if (*s == '"' && p[-1] == '"' && p > s + 1) { + if ((*s == '"') && (p[-1] == '"') && (p > s + 1)) { s++; p--; } @@ -4589,8 +6516,8 @@ base64_encode(const unsigned char *src, int src_len, char *dst) for (i = j = 0; i < src_len; i += 3) { a = src[i]; - b = i + 1 >= src_len ? 0 : src[i + 1]; - c = i + 2 >= src_len ? 0 : src[i + 2]; + b = ((i + 1) >= src_len) ? 0 : src[i + 1]; + c = ((i + 2) >= src_len) ? 0 : src[i + 2]; dst[j++] = b64[a >> 2]; dst[j++] = b64[((a & 3) << 4) | (b >> 4)]; @@ -4613,13 +6540,13 @@ base64_encode(const unsigned char *src, int src_len, char *dst) static unsigned char b64reverse(char letter) { - if (letter >= 'A' && letter <= 'Z') { + if ((letter >= 'A') && (letter <= 'Z')) { return letter - 'A'; } - if (letter >= 'a' && letter <= 'z') { + if ((letter >= 'a') && (letter <= 'z')) { return letter - 'a' + 26; } - if (letter >= '0' && letter <= '9') { + if ((letter >= '0') && (letter <= '9')) { return letter - '0' + 52; } if (letter == '+') { @@ -4649,17 +6576,17 @@ base64_decode(const unsigned char *src, int src_len, char *dst, size_t *dst_len) return i; } - b = b64reverse(i + 1 >= src_len ? 0 : src[i + 1]); + b = b64reverse(((i + 1) >= src_len) ? 0 : src[i + 1]); if (b >= 254) { return i + 1; } - c = b64reverse(i + 2 >= src_len ? 0 : src[i + 2]); + c = b64reverse(((i + 2) >= src_len) ? 0 : src[i + 2]); if (c == 254) { return i + 2; } - d = b64reverse(i + 3 >= src_len ? 0 : src[i + 3]); + d = b64reverse(((i + 3) >= src_len) ? 0 : src[i + 3]); if (d == 254) { return i + 3; } @@ -4682,25 +6609,113 @@ is_put_or_delete_method(const struct mg_connection *conn) { if (conn) { const char *s = conn->request_info.request_method; - return s != NULL && (!strcmp(s, "PUT") || !strcmp(s, "DELETE") - || !strcmp(s, "MKCOL") || !strcmp(s, "PATCH")); + return (s != NULL) && (!strcmp(s, "PUT") || !strcmp(s, "DELETE") + || !strcmp(s, "MKCOL") || !strcmp(s, "PATCH")); } return 0; } +#if !defined(NO_FILES) +static int +extention_matches_script( + struct mg_connection *conn, /* in: request (must be valid) */ + const char *filename /* in: filename (must be valid) */ + ) +{ +#if !defined(NO_CGI) + if (match_prefix(conn->ctx->config[CGI_EXTENSIONS], + strlen(conn->ctx->config[CGI_EXTENSIONS]), + filename) > 0) { + return 1; + } +#endif +#if defined(USE_LUA) + if (match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS], + strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]), + filename) > 0) { + return 1; + } +#endif +#if defined(USE_DUKTAPE) + if (match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS], + strlen(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]), + filename) > 0) { + return 1; + } +#endif + /* filename and conn could be unused, if all preocessor conditions + * are false (no script language supported). */ + (void)filename; + (void)conn; + + return 0; +} + + +/* For given directory path, substitute it to valid index file. + * Return 1 if index file has been found, 0 if not found. + * If the file is found, it's stats is returned in stp. */ +static int +substitute_index_file(struct mg_connection *conn, + char *path, + size_t path_len, + struct mg_file_stat *filestat) +{ + const char *list = conn->ctx->config[INDEX_FILES]; + struct vec filename_vec; + size_t n = strlen(path); + int found = 0; + + /* The 'path' given to us points to the directory. Remove all trailing + * directory separator characters from the end of the path, and + * then append single directory separator character. */ + while ((n > 0) && (path[n - 1] == '/')) { + n--; + } + path[n] = '/'; + + /* Traverse index files list. For each entry, append it to the given + * path and see if the file exists. If it exists, break the loop */ + while ((list = next_option(list, &filename_vec, NULL)) != NULL) { + /* Ignore too long entries that may overflow path buffer */ + if (filename_vec.len > (path_len - (n + 2))) { + continue; + } + + /* Prepare full path to the index file */ + mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1); + + /* Does it exist? */ + if (mg_stat(conn, path, filestat)) { + /* Yes it does, break the loop */ + found = 1; + break; + } + } + + /* If no index file exists, restore directory path */ + if (!found) { + path[n] = '\0'; + } + + return found; +} +#endif + + static void -interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */ - char *filename, /* out: filename */ - size_t filename_buf_len, /* in: size of filename buffer */ - struct file *filep, /* out: file structure */ - int *is_found, /* out: file is found (directly) */ - int *is_script_resource, /* out: handled by a script? */ - int *is_websocket_request, /* out: websocket connetion? */ - int *is_put_or_delete_request /* out: put/delete a file? */ +interpret_uri(struct mg_connection *conn, /* in/out: request (must be valid) */ + char *filename, /* out: filename */ + size_t filename_buf_len, /* in: size of filename buffer */ + struct mg_file_stat *filestat, /* out: file status structure */ + int *is_found, /* out: file found (directly) */ + int *is_script_resource, /* out: handled by a script? */ + int *is_websocket_request, /* out: websocket connetion? */ + int *is_put_or_delete_request /* out: put/delete a file? */ ) { -/* TODO (high): Restructure this function */ + char const *accept_encoding; #if !defined(NO_FILES) const char *uri = conn->request_info.local_uri; @@ -4709,21 +6724,27 @@ interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */ struct vec a, b; int match_len; char gz_path[PATH_MAX]; - char const *accept_encoding; int truncated; -#if !defined(NO_CGI) || defined(USE_LUA) - char *p; +#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) + char *tmp_str; + size_t tmp_str_len, sep_pos; + int allow_substitute_script_subresources; #endif #else (void)filename_buf_len; /* unused if NO_FILES is defined */ #endif - memset(filep, 0, sizeof(*filep)); + /* Step 1: Set all initially unknown outputs to zero */ + memset(filestat, 0, sizeof(*filestat)); *filename = 0; *is_found = 0; *is_script_resource = 0; + + /* Step 2: Check if the request attempts to modify the file system */ *is_put_or_delete_request = is_put_or_delete_method(conn); +/* Step 3: Check if it is a websocket request, and modify the document + * root if required */ #if defined(USE_WEBSOCKET) *is_websocket_request = is_websocket_protocol(conn); #if !defined(NO_FILES) @@ -4735,7 +6756,16 @@ interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */ *is_websocket_request = 0; #endif /* USE_WEBSOCKET */ + /* Step 4: Check if gzip encoded response is allowed */ + conn->accept_gzip = 0; + if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) { + if (strstr(accept_encoding, "gzip") != NULL) { + conn->accept_gzip = 1; + } + } + #if !defined(NO_FILES) + /* Step 5: If there is no root directory, don't look for files. */ /* Note that root == NULL is a regular use case here. This occurs, * if all requests are handled by callbacks, so the WEBSOCKET_ROOT * config is not required. */ @@ -4745,9 +6775,10 @@ interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */ return; } - /* Using buf_len - 1 because memmove() for PATH_INFO may shift part - * of the path one byte on the right. - * If document_root is NULL, leave the file empty. */ + /* Step 6: Determine the local file path from the root path and the + * request uri. */ + /* Using filename_buf_len - 1 because memmove() for PATH_INFO may shift + * part of the path one byte on the right. */ mg_snprintf( conn, &truncated, filename, filename_buf_len - 1, "%s%s", root, uri); @@ -4755,7 +6786,8 @@ interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */ goto interpret_cleanup; } - rewrite = conn->ctx->config[REWRITE]; + /* Step 7: URI rewriting */ + rewrite = conn->ctx->config[URL_REWRITE_PATTERN]; while ((rewrite = next_option(rewrite, &a, &b)) != NULL) { if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) { mg_snprintf(conn, @@ -4774,112 +6806,180 @@ interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */ goto interpret_cleanup; } + /* Step 8: Check if the file exists at the server */ /* Local file path and name, corresponding to requested URI * is now stored in "filename" variable. */ - if (mg_stat(conn, filename, filep)) { -#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) - /* File exists. Check if it is a script type. */ - if (0 -#if !defined(NO_CGI) - || match_prefix(conn->ctx->config[CGI_EXTENSIONS], - strlen(conn->ctx->config[CGI_EXTENSIONS]), - filename) > 0 -#endif -#if defined(USE_LUA) - || match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS], - strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]), - filename) > 0 -#endif -#if defined(USE_DUKTAPE) - || match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS], - strlen( - conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]), - filename) > 0 -#endif - ) { - /* The request addresses a CGI script or a Lua script. The URI - * corresponds to the script itself (like /path/script.cgi), - * and there is no additional resource path - * (like /path/script.cgi/something). + if (mg_stat(conn, filename, filestat)) { + /* 8.1: File exists. */ + *is_found = 1; + + /* 8.2: Check if it is a script type. */ + if (extention_matches_script(conn, filename)) { + /* The request addresses a CGI resource, Lua script or + * server-side javascript. + * The URI corresponds to the script itself (like + * /path/script.cgi), and there is no additional resource + * path (like /path/script.cgi/something). * Requests that modify (replace or delete) a resource, like * PUT and DELETE requests, should replace/delete the script * file. * Requests that read or write from/to a resource, like GET and * POST requests, should call the script and return the * generated response. */ - *is_script_resource = !*is_put_or_delete_request; + *is_script_resource = (!*is_put_or_delete_request); + } + + /* 8.3: If the request target is a directory, there could be + * a substitute file (index.html, index.cgi, ...). */ + if (filestat->is_directory) { + /* Use a local copy here, since substitute_index_file will + * change the content of the file status */ + struct mg_file_stat tmp_filestat; + memset(&tmp_filestat, 0, sizeof(tmp_filestat)); + + if (substitute_index_file( + conn, filename, filename_buf_len, &tmp_filestat)) { + + /* Substitute file found. Copy stat to the output, then + * check if the file is a script file */ + *filestat = tmp_filestat; + + if (extention_matches_script(conn, filename)) { + /* Substitute file is a script file */ + *is_script_resource = 1; + } else { + /* Substitute file is a regular file */ + *is_script_resource = 0; + *is_found = (mg_stat(conn, filename, filestat) ? 1 : 0); + } + } + /* If there is no substitute file, the server could return + * a directory listing in a later step */ } -#endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */ - *is_found = 1; return; } + /* Step 9: Check for zipped files: */ /* If we can't find the actual file, look for the file * with the same name but a .gz extension. If we find it, * use that and set the gzipped flag in the file struct * to indicate that the response need to have the content- * encoding: gzip header. * We can only do this if the browser declares support. */ - if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) { - if (strstr(accept_encoding, "gzip") != NULL) { - mg_snprintf( - conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", filename); + if (conn->accept_gzip) { + mg_snprintf( + conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", filename); - if (truncated) { - goto interpret_cleanup; - } + if (truncated) { + goto interpret_cleanup; + } - if (mg_stat(conn, gz_path, filep)) { - if (filep) { - filep->gzipped = 1; - *is_found = 1; - } - /* Currently gz files can not be scripts. */ - return; + if (mg_stat(conn, gz_path, filestat)) { + if (filestat) { + filestat->is_gzipped = 1; + *is_found = 1; } + /* Currently gz files can not be scripts. */ + return; } } #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) + /* Step 10: Script resources may handle sub-resources */ /* Support PATH_INFO for CGI scripts. */ - for (p = filename + strlen(filename); p > filename + 1; p--) { - if (*p == '/') { - *p = '\0'; - if ((0 -#if !defined(NO_CGI) - || match_prefix(conn->ctx->config[CGI_EXTENSIONS], - strlen(conn->ctx->config[CGI_EXTENSIONS]), - filename) > 0 -#endif -#if defined(USE_LUA) - || match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS], - strlen( - conn->ctx->config[LUA_SCRIPT_EXTENSIONS]), - filename) > 0 -#endif -#if defined(USE_DUKTAPE) - || match_prefix( - conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS], - strlen(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]), - filename) > 0 -#endif - ) && mg_stat(conn, filename, filep)) { - /* Shift PATH_INFO block one character right, e.g. - * "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00" - * conn->path_info is pointing to the local variable "path" - * declared in handle_request(), so PATH_INFO is not valid - * after handle_request returns. */ - conn->path_info = p + 1; - memmove(p + 2, p + 1, strlen(p + 1) + 1); /* +1 is for - * trailing \0 */ - p[1] = '/'; - *is_script_resource = 1; - break; - } else { - *p = '/'; + tmp_str_len = strlen(filename); + tmp_str = (char *)mg_malloc_ctx(tmp_str_len + PATH_MAX + 1, conn->ctx); + if (!tmp_str) { + /* Out of memory */ + goto interpret_cleanup; + } + memcpy(tmp_str, filename, tmp_str_len + 1); + + /* Check config, if index scripts may have sub-resources */ + allow_substitute_script_subresources = + !mg_strcasecmp(conn->ctx->config[ALLOW_INDEX_SCRIPT_SUB_RES], "yes"); + + sep_pos = tmp_str_len; + while (sep_pos > 0) { + sep_pos--; + if (tmp_str[sep_pos] == '/') { + int is_script = 0, does_exist = 0; + + tmp_str[sep_pos] = 0; + if (tmp_str[0]) { + is_script = extention_matches_script(conn, tmp_str); + does_exist = mg_stat(conn, tmp_str, filestat); } + + if (does_exist && is_script) { + filename[sep_pos] = 0; + memmove(filename + sep_pos + 2, + filename + sep_pos + 1, + strlen(filename + sep_pos + 1) + 1); + conn->path_info = filename + sep_pos + 1; + filename[sep_pos + 1] = '/'; + *is_script_resource = 1; + *is_found = 1; + break; + } + + if (allow_substitute_script_subresources) { + if (substitute_index_file( + conn, tmp_str, tmp_str_len + PATH_MAX, filestat)) { + + /* some intermediate directory has an index file */ + if (extention_matches_script(conn, tmp_str)) { + + char *tmp_str2; + + DEBUG_TRACE("Substitute script %s serving path %s", + tmp_str, + filename); + + /* this index file is a script */ + tmp_str2 = mg_strdup(filename + sep_pos + 1); + mg_snprintf(conn, + &truncated, + filename, + filename_buf_len, + "%s//%s", + tmp_str, + tmp_str2); + mg_free(tmp_str2); + + if (truncated) { + mg_free(tmp_str); + goto interpret_cleanup; + } + sep_pos = strlen(tmp_str); + filename[sep_pos] = 0; + conn->path_info = filename + sep_pos + 1; + *is_script_resource = 1; + *is_found = 1; + break; + + } else { + + DEBUG_TRACE("Substitute file %s serving path %s", + tmp_str, + filename); + + /* non-script files will not have sub-resources */ + filename[sep_pos] = 0; + conn->path_info = 0; + *is_script_resource = 0; + *is_found = 0; + break; + } + } + } + + tmp_str[sep_pos] = '/'; } } + + mg_free(tmp_str); + #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */ #endif /* !defined(NO_FILES) */ return; @@ -4887,7 +6987,7 @@ interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */ #if !defined(NO_FILES) /* Reset all outputs */ interpret_cleanup: - memset(filep, 0, sizeof(*filep)); + memset(filestat, 0, sizeof(*filestat)); *filename = 0; *is_found = 0; *is_script_resource = 0; @@ -4898,38 +6998,43 @@ interpret_cleanup: /* Check whether full request is buffered. Return: - * -1 if request is malformed - * 0 if request is not yet fully buffered + * -1 if request or response is malformed + * 0 if request or response is not yet fully buffered * >0 actual request length, including last \r\n\r\n */ static int -get_request_len(const char *buf, int buflen) +get_http_header_len(const char *buf, int buflen) { - const char *s, *e; - int len = 0; - int in_content = 0; + int i; + for (i = 0; i < buflen; i++) { + /* Do an unsigned comparison in some conditions below */ + const unsigned char c = ((const unsigned char *)buf)[i]; - for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++) { - /* Control characters are not allowed but >=128 is. */ - if (!in_content && !isprint(*(const unsigned char *)s) && *s != '\r' - && *s != '\n' - && *(const unsigned char *)s < 128) { - len = -1; - break; /* [i_a] abort scan as soon as one malformed character is - * found; */ - /* don't let subsequent \r\n\r\n win us over anyhow */ - } else if (s[0] == '\n' && s[1] == '\n') { - len = (int)(s - buf) + 2; - } else if (s[0] == '\n' && &s[1] < e && s[1] == '\r' && s[2] == '\n') { - len = (int)(s - buf) + 3; - in_content = 0; + if ((c < 128) && ((char)c != '\r') && ((char)c != '\n') + && !isprint(c)) { + /* abort scan as soon as one malformed character is found */ + return -1; } - if (!in_content && *s == ':') { - in_content = 1; + if (i < buflen - 1) { + if ((buf[i] == '\n') && (buf[i + 1] == '\n')) { + /* Two newline, no carriage return - not standard compliant, + * but + * it + * should be accepted */ + return i + 2; + } + } + + if (i < buflen - 3) { + if ((buf[i] == '\r') && (buf[i + 1] == '\n') && (buf[i + 2] == '\r') + && (buf[i + 3] == '\n')) { + /* Two \r\n - standard compliant */ + return i + 4; + } } } - return len; + return 0; } @@ -5014,14 +7119,18 @@ remove_double_dots_and_double_slashes(char *s) { char *p = s; + while ((s[0] == '.') && (s[1] == '.')) { + s++; + } + while (*s != '\0') { *p++ = *s++; - if (s[-1] == '/' || s[-1] == '\\') { + if ((s[-1] == '/') || (s[-1] == '\\')) { /* Skip all following slashes, backslashes and double-dots */ while (s[0] != '\0') { - if (s[0] == '/' || s[0] == '\\') { + if ((s[0] == '/') || (s[0] == '\\')) { s++; - } else if (s[0] == '.' && s[1] == '.') { + } else if ((s[0] == '.') && (s[1] == '.')) { s += 2; } else { break; @@ -5038,7 +7147,8 @@ static const struct { size_t ext_len; const char *mime_type; } builtin_mime_types[] = { - /* IANA registered MIME types (http://www.iana.org/assignments/media-types) + /* IANA registered MIME types + * (http://www.iana.org/assignments/media-types) * application types */ {".doc", 4, "application/msword"}, {".eps", 4, "application/postscript"}, @@ -5144,8 +7254,8 @@ mg_get_builtin_mime_type(const char *path) for (i = 0; builtin_mime_types[i].extension != NULL; i++) { ext = path + (path_len - builtin_mime_types[i].ext_len); - if (path_len > builtin_mime_types[i].ext_len - && mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) { + if ((path_len > builtin_mime_types[i].ext_len) + && (mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0)) { return builtin_mime_types[i].mime_type; } } @@ -5165,7 +7275,10 @@ get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec) path_len = strlen(path); - if (ctx == NULL || vec == NULL) { + if ((ctx == NULL) || (vec == NULL)) { + if (vec != NULL) { + memset(vec, '\0', sizeof(struct vec)); + } return; } @@ -5201,7 +7314,8 @@ bin2str(char *to, const unsigned char *p, size_t len) } -/* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. */ +/* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. + */ char * mg_md5(char buf[33], ...) { @@ -5238,9 +7352,8 @@ check_password(const char *method, char ha2[32 + 1], expected_response[32 + 1]; /* Some of the parameters may be NULL */ - if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL - || qop == NULL - || response == NULL) { + if ((method == NULL) || (nonce == NULL) || (nc == NULL) || (cnonce == NULL) + || (qop == NULL) || (response == NULL)) { return 0; } @@ -5271,25 +7384,30 @@ check_password(const char *method, /* Use the global passwords file, if specified by auth_gpass option, * or search for .htpasswd in the requested directory. */ static void -open_auth_file(struct mg_connection *conn, const char *path, struct file *filep) +open_auth_file(struct mg_connection *conn, + const char *path, + struct mg_file *filep) { - if (conn != NULL && conn->ctx != NULL) { + if ((conn != NULL) && (conn->ctx != NULL)) { char name[PATH_MAX]; const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE]; - struct file file = STRUCT_FILE_INITIALIZER; int truncated; if (gpass != NULL) { /* Use global passwords file */ - if (!mg_fopen(conn, gpass, "r", filep)) { + if (!mg_fopen(conn, gpass, MG_FOPEN_MODE_READ, filep)) { #ifdef DEBUG + /* Use mg_cry here, since gpass has been configured. */ mg_cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO)); #endif } - /* Important: using local struct file to test path for is_directory - * flag. If filep is used, mg_stat() makes it appear as if auth file - * was opened. */ - } else if (mg_stat(conn, path, &file) && file.is_directory) { + /* Important: using local struct mg_file to test path for + * is_directory flag. If filep is used, mg_stat() makes it + * appear as if auth file was opened. + * TODO(mid): Check if this is still required after rewriting + * mg_stat */ + } else if (mg_stat(conn, path, &filep->stat) + && filep->stat.is_directory) { mg_snprintf(conn, &truncated, name, @@ -5298,9 +7416,12 @@ open_auth_file(struct mg_connection *conn, const char *path, struct file *filep) path, PASSWORDS_FILE_NAME); - if (truncated || !mg_fopen(conn, name, "r", filep)) { + if (truncated || !mg_fopen(conn, name, MG_FOPEN_MODE_READ, filep)) { #ifdef DEBUG - mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO)); + /* Don't use mg_cry here, but only a trace, since this is + * a typical case. It will occur for every directory + * without a password file. */ + DEBUG_TRACE("fopen(%s): %s", name, strerror(ERRNO)); #endif } } else { @@ -5319,9 +7440,12 @@ open_auth_file(struct mg_connection *conn, const char *path, struct file *filep) p, PASSWORDS_FILE_NAME); - if (truncated || !mg_fopen(conn, name, "r", filep)) { + if (truncated || !mg_fopen(conn, name, MG_FOPEN_MODE_READ, filep)) { #ifdef DEBUG - mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO)); + /* Don't use mg_cry here, but only a trace, since this is + * a typical case. It will occur for every directory + * without a password file. */ + DEBUG_TRACE("fopen(%s): %s", name, strerror(ERRNO)); #endif } } @@ -5351,7 +7475,7 @@ parse_auth_header(struct mg_connection *conn, } (void)memset(ah, 0, sizeof(*ah)); - if ((auth_header = mg_get_header(conn, "Authorization")) == NULL + if (((auth_header = mg_get_header(conn, "Authorization")) == NULL) || mg_strncasecmp(auth_header, "Digest ", 7) != 0) { return 0; } @@ -5367,7 +7491,8 @@ parse_auth_header(struct mg_connection *conn, s++; } name = skip_quoted(&s, "=", " ", 0); - /* Value is either quote-delimited, or ends at first comma or space. */ + /* Value is either quote-delimited, or ends at first comma or space. + */ if (s[0] == '\"') { s++; value = skip_quoted(&s, "\"", " ", '\\'); @@ -5431,6 +7556,8 @@ parse_auth_header(struct mg_connection *conn, if (nonce >= ((uint64_t)conn->ctx->start_time + conn->ctx->nonce_count)) { return 0; } +#else + (void)nonce; #endif /* CGI needs it as REMOTE_USER */ @@ -5445,7 +7572,7 @@ parse_auth_header(struct mg_connection *conn, static const char * -mg_fgets(char *buf, size_t size, struct file *filep, char **p) +mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p) { const char *eof; size_t len; @@ -5455,8 +7582,8 @@ mg_fgets(char *buf, size_t size, struct file *filep, char **p) return NULL; } - if (filep->membuf != NULL && *p != NULL) { - memend = (const char *)&filep->membuf[filep->size]; + if ((filep->access.membuf != NULL) && (*p != NULL)) { + memend = (const char *)&filep->access.membuf[filep->stat.size]; /* Search for \n from p till the end of stream */ eof = (char *)memchr(*p, '\n', (size_t)(memend - *p)); if (eof != NULL) { @@ -5464,43 +7591,57 @@ mg_fgets(char *buf, size_t size, struct file *filep, char **p) } else { eof = memend; /* Copy remaining data */ } - len = (size_t)(eof - *p) > size - 1 ? size - 1 : (size_t)(eof - *p); + len = + ((size_t)(eof - *p) > (size - 1)) ? (size - 1) : (size_t)(eof - *p); memcpy(buf, *p, len); buf[len] = '\0'; *p += len; return len ? eof : NULL; - } else if (filep->fp != NULL) { - return fgets(buf, (int)size, filep->fp); + } else if (filep->access.fp != NULL) { + return fgets(buf, (int)size, filep->access.fp); } else { return NULL; } } +/* Define the initial recursion depth for procesesing htpasswd files that + * include other htpasswd + * (or even the same) files. It is not difficult to provide a file or files + * s.t. they force civetweb + * to infinitely recurse and then crash. + */ +#define INITIAL_DEPTH 9 +#if INITIAL_DEPTH <= 0 +#error Bad INITIAL_DEPTH for recursion, set to at least 1 +#endif + struct read_auth_file_struct { struct mg_connection *conn; struct ah ah; - char *domain; + const char *domain; char buf[256 + 256 + 40]; - char *f_user; - char *f_domain; - char *f_ha1; + const char *f_user; + const char *f_domain; + const char *f_ha1; }; static int -read_auth_file(struct file *filep, struct read_auth_file_struct *workdata) +read_auth_file(struct mg_file *filep, + struct read_auth_file_struct *workdata, + int depth) { char *p; int is_authorized = 0; - struct file fp; + struct mg_file fp; size_t l; - if (!filep || !workdata) { + if (!filep || !workdata || (0 == depth)) { return 0; } /* Loop over passwords file */ - p = (char *)filep->membuf; + p = (char *)filep->access.membuf; while (mg_fgets(workdata->buf, sizeof(workdata->buf), filep, &p) != NULL) { l = strlen(workdata->buf); while (l > 0) { @@ -5519,14 +7660,27 @@ read_auth_file(struct file *filep, struct read_auth_file_struct *workdata) if (workdata->f_user[0] == ':') { /* user names may not contain a ':' and may not be empty, - * so lines starting with ':' may be used for a special purpose */ + * so lines starting with ':' may be used for a special purpose + */ if (workdata->f_user[1] == '#') { /* :# is a comment */ continue; } else if (!strncmp(workdata->f_user + 1, "include=", 8)) { - if (mg_fopen(workdata->conn, workdata->f_user + 9, "r", &fp)) { - is_authorized = read_auth_file(&fp, workdata); - mg_fclose(&fp); + if (mg_fopen(workdata->conn, + workdata->f_user + 9, + MG_FOPEN_MODE_READ, + &fp)) { + is_authorized = read_auth_file(&fp, workdata, depth - 1); + (void)mg_fclose( + &fp.access); /* ignore error on read only file */ + + /* No need to continue processing files once we have a + * match, since nothing will reset it back + * to 0. + */ + if (is_authorized) { + return is_authorized; + } } else { mg_cry(workdata->conn, "%s: cannot open authorization file: %s", @@ -5552,7 +7706,7 @@ read_auth_file(struct file *filep, struct read_auth_file_struct *workdata) workdata->buf); continue; } - *(workdata->f_domain) = 0; + *(char *)(workdata->f_domain) = 0; (workdata->f_domain)++; workdata->f_ha1 = strchr(workdata->f_domain, ':'); @@ -5563,7 +7717,7 @@ read_auth_file(struct file *filep, struct read_auth_file_struct *workdata) workdata->buf); continue; } - *(workdata->f_ha1) = 0; + *(char *)(workdata->f_ha1) = 0; (workdata->f_ha1)++; if (!strcmp(workdata->ah.user, workdata->f_user) @@ -5585,7 +7739,7 @@ read_auth_file(struct file *filep, struct read_auth_file_struct *workdata) /* Authorize against the opened passwords file. Return 1 if authorized. */ static int -authorize(struct mg_connection *conn, struct file *filep) +authorize(struct mg_connection *conn, struct mg_file *filep, const char *realm) { struct read_auth_file_struct workdata; char buf[MG_BUF_LEN]; @@ -5600,9 +7754,38 @@ authorize(struct mg_connection *conn, struct file *filep) if (!parse_auth_header(conn, buf, sizeof(buf), &workdata.ah)) { return 0; } - workdata.domain = conn->ctx->config[AUTHENTICATION_DOMAIN]; - return read_auth_file(filep, &workdata); + if (realm) { + workdata.domain = realm; + } else { + workdata.domain = conn->ctx->config[AUTHENTICATION_DOMAIN]; + } + + return read_auth_file(filep, &workdata, INITIAL_DEPTH); +} + + +/* Public function to check http digest authentication header */ +int +mg_check_digest_access_authentication(struct mg_connection *conn, + const char *realm, + const char *filename) +{ + struct mg_file file = STRUCT_FILE_INITIALIZER; + int auth; + + if (!conn || !filename) { + return -1; + } + if (!mg_fopen(conn, filename, MG_FOPEN_MODE_READ, &file)) { + return -2; + } + + auth = authorize(conn, &file, realm); + + mg_fclose(&file.access); + + return auth; } @@ -5613,7 +7796,7 @@ check_authorization(struct mg_connection *conn, const char *path) char fname[PATH_MAX]; struct vec uri_vec, filename_vec; const char *list; - struct file file = STRUCT_FILE_INITIALIZER; + struct mg_file file = STRUCT_FILE_INITIALIZER; int authorized = 1, truncated; if (!conn || !conn->ctx) { @@ -5631,7 +7814,8 @@ check_authorization(struct mg_connection *conn, const char *path) (int)filename_vec.len, filename_vec.ptr); - if (truncated || !mg_fopen(conn, fname, "r", &file)) { + if (truncated + || !mg_fopen(conn, fname, MG_FOPEN_MODE_READ, &file)) { mg_cry(conn, "%s: cannot open %s: %s", __func__, @@ -5642,52 +7826,70 @@ check_authorization(struct mg_connection *conn, const char *path) } } - if (!is_file_opened(&file)) { + if (!is_file_opened(&file.access)) { open_auth_file(conn, path, &file); } - if (is_file_opened(&file)) { - authorized = authorize(conn, &file); - mg_fclose(&file); + if (is_file_opened(&file.access)) { + authorized = authorize(conn, &file, NULL); + (void)mg_fclose(&file.access); /* ignore error on read only file */ } return authorized; } +/* Internal function. Assumes conn is valid */ static void -send_authorization_request(struct mg_connection *conn) +send_authorization_request(struct mg_connection *conn, const char *realm) { char date[64]; time_t curtime = time(NULL); + uint64_t nonce = (uint64_t)(conn->ctx->start_time); - if (conn && conn->ctx) { - uint64_t nonce = (uint64_t)(conn->ctx->start_time); - - (void)pthread_mutex_lock(&conn->ctx->nonce_mutex); - nonce += conn->ctx->nonce_count; - ++conn->ctx->nonce_count; - (void)pthread_mutex_unlock(&conn->ctx->nonce_mutex); - - nonce ^= conn->ctx->auth_nonce_mask; - conn->status_code = 401; - conn->must_close = 1; - - gmt_time_string(date, sizeof(date), &curtime); - - mg_printf(conn, "HTTP/1.1 401 Unauthorized\r\n"); - send_no_cache_header(conn); - mg_printf(conn, - "Date: %s\r\n" - "Connection: %s\r\n" - "Content-Length: 0\r\n" - "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", " - "nonce=\"%" UINT64_FMT "\"\r\n\r\n", - date, - suggest_connection_header(conn), - conn->ctx->config[AUTHENTICATION_DOMAIN], - nonce); + if (!realm) { + realm = conn->ctx->config[AUTHENTICATION_DOMAIN]; } + + (void)pthread_mutex_lock(&conn->ctx->nonce_mutex); + nonce += conn->ctx->nonce_count; + ++conn->ctx->nonce_count; + (void)pthread_mutex_unlock(&conn->ctx->nonce_mutex); + + nonce ^= conn->ctx->auth_nonce_mask; + conn->status_code = 401; + conn->must_close = 1; + + gmt_time_string(date, sizeof(date), &curtime); + + mg_printf(conn, "HTTP/1.1 401 Unauthorized\r\n"); + send_no_cache_header(conn); + send_additional_header(conn); + mg_printf(conn, + "Date: %s\r\n" + "Connection: %s\r\n" + "Content-Length: 0\r\n" + "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", " + "nonce=\"%" UINT64_FMT "\"\r\n\r\n", + date, + suggest_connection_header(conn), + realm, + nonce); +} + + +/* Interface function. Parameters are provided by the user, so do + * at least some basic checks. + */ +int +mg_send_digest_access_authentication_request(struct mg_connection *conn, + const char *realm) +{ + if (conn && conn->ctx) { + send_authorization_request(conn, realm); + return 0; + } + return -1; } @@ -5696,13 +7898,14 @@ static int is_authorized_for_put(struct mg_connection *conn) { if (conn) { - struct file file = STRUCT_FILE_INITIALIZER; + struct mg_file file = STRUCT_FILE_INITIALIZER; const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE]; int ret = 0; - if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) { - ret = authorize(conn, &file); - mg_fclose(&file); + if (passfile != NULL + && mg_fopen(conn, passfile, MG_FOPEN_MODE_READ, &file)) { + ret = authorize(conn, &file, NULL); + (void)mg_fclose(&file.access); /* ignore error on read only file */ } return ret; @@ -5726,16 +7929,17 @@ mg_modify_passwords_file(const char *fname, fp = fp2 = NULL; /* Regard empty password as no password - remove user record. */ - if (pass != NULL && pass[0] == '\0') { + if ((pass != NULL) && (pass[0] == '\0')) { pass = NULL; } /* Other arguments must not be empty */ - if (fname == NULL || domain == NULL || user == NULL) { + if ((fname == NULL) || (domain == NULL) || (user == NULL)) { return 0; } - /* Using the given file format, user name and domain must not contain ':' + /* Using the given file format, user name and domain must not contain + * ':' */ if (strchr(user, ':') != NULL) { return 0; @@ -5746,7 +7950,7 @@ mg_modify_passwords_file(const char *fname, /* Do not allow control characters like newline in user name and domain. * Do not allow excessively long names either. */ - for (i = 0; i < 255 && user[i] != 0; i++) { + for (i = 0; ((i < 255) && (user[i] != 0)); i++) { if (iscntrl(user[i])) { return 0; } @@ -5754,7 +7958,7 @@ mg_modify_passwords_file(const char *fname, if (user[i]) { return 0; } - for (i = 0; i < 255 && domain[i] != 0; i++) { + for (i = 0; ((i < 255) && (domain[i] != 0)); i++) { if (iscntrl(domain[i])) { return 0; } @@ -5806,7 +8010,7 @@ mg_modify_passwords_file(const char *fname, } /* If new user, just add it */ - if (!found && pass != NULL) { + if (!found && (pass != NULL)) { mg_md5(ha1, user, ":", domain, ":", pass, NULL); fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); } @@ -5826,7 +8030,7 @@ mg_modify_passwords_file(const char *fname, static int is_valid_port(unsigned long port) { - return port < 0xffff; + return (port <= 0xffff); } @@ -5855,7 +8059,7 @@ mg_inet_pton(int af, const char *src, void *dst, size_t dstlen) ressave = res; while (res) { - if (dstlen >= res->ai_addrlen) { + if (dstlen >= (size_t)res->ai_addrlen) { memcpy(dst, res->ai_addr, res->ai_addrlen); func_ret = 1; } @@ -5896,7 +8100,7 @@ connect_socket(struct mg_context *ctx /* may be NULL */, return 0; } - if (port < 0 || !is_valid_port((unsigned)port)) { + if ((port <= 0) || !is_valid_port((unsigned)port)) { mg_snprintf(NULL, NULL, /* No truncation check for ebuf */ ebuf, @@ -5906,7 +8110,19 @@ connect_socket(struct mg_context *ctx /* may be NULL */, return 0; } -#ifndef NO_SSL_DL +#if !defined(NO_SSL) +#if !defined(NO_SSL_DL) +#ifdef OPENSSL_API_1_1 + if (use_ssl && (TLS_client_method == NULL)) { + mg_snprintf(NULL, + NULL, /* No truncation check for ebuf */ + ebuf, + ebuf_len, + "%s", + "SSL is not initialized"); + return 0; + } +#else if (use_ssl && (SSLv23_client_method == NULL)) { mg_snprintf(NULL, NULL, /* No truncation check for ebuf */ @@ -5916,23 +8132,33 @@ connect_socket(struct mg_context *ctx /* may be NULL */, "SSL is not initialized"); return 0; } -#endif + +#endif /* OPENSSL_API_1_1 */ +#else + (void)use_ssl; +#endif /* NO_SSL_DL */ +#else + (void)use_ssl; +#endif /* !defined(NO_SSL) */ if (mg_inet_pton(AF_INET, host, &sa->sin, sizeof(sa->sin))) { + sa->sin.sin_family = AF_INET; sa->sin.sin_port = htons((uint16_t)port); ip_ver = 4; #ifdef USE_IPV6 } else if (mg_inet_pton(AF_INET6, host, &sa->sin6, sizeof(sa->sin6))) { + sa->sin6.sin6_family = AF_INET6; sa->sin6.sin6_port = htons((uint16_t)port); ip_ver = 6; } else if (host[0] == '[') { /* While getaddrinfo on Windows will work with [::1], * getaddrinfo on Linux only works with ::1 (without []). */ size_t l = strlen(host + 1); - char *h = l > 1 ? mg_strdup(host + 1) : NULL; + char *h = (l > 1) ? mg_strdup(host + 1) : NULL; if (h) { h[l - 1] = 0; if (mg_inet_pton(AF_INET6, h, &sa->sin6, sizeof(sa->sin6))) { + sa->sin6.sin6_family = AF_INET6; sa->sin6.sin6_port = htons((uint16_t)port); ip_ver = 6; } @@ -5976,7 +8202,12 @@ connect_socket(struct mg_context *ctx /* may be NULL */, && (connect(*sock, (struct sockaddr *)&sa->sin, sizeof(sa->sin)) == 0)) { /* connected with IPv4 */ - return 1; + if (0 == set_non_blocking_mode(*sock)) { + /* Ok */ + return 1; + } + /* failed */ + /* TODO: specific error message */ } #ifdef USE_IPV6 @@ -5984,7 +8215,12 @@ connect_socket(struct mg_context *ctx /* may be NULL */, && (connect(*sock, (struct sockaddr *)&sa->sin6, sizeof(sa->sin6)) == 0)) { /* connected with IPv6 */ - return 1; + if (0 == set_non_blocking_mode(*sock)) { + /* Ok */ + return 1; + } + /* failed */ + /* TODO: specific error message */ } #endif @@ -5999,6 +8235,7 @@ connect_socket(struct mg_context *ctx /* may be NULL */, strerror(ERRNO)); closesocket(*sock); *sock = INVALID_SOCKET; + return 0; } @@ -6011,9 +8248,9 @@ mg_url_encode(const char *src, char *dst, size_t dst_len) char *pos = dst; const char *end = dst + dst_len - 1; - for (; *src != '\0' && pos < end; src++, pos++) { + for (; ((*src != '\0') && (pos < end)); src++, pos++) { if (isalnum(*(const unsigned char *)src) - || strchr(dont_escape, *(const unsigned char *)src) != NULL) { + || (strchr(dont_escape, *(const unsigned char *)src) != NULL)) { *pos = *src; } else if (pos + 2 < end) { pos[0] = '%'; @@ -6029,13 +8266,21 @@ mg_url_encode(const char *src, char *dst, size_t dst_len) return (*src == '\0') ? (int)(pos - dst) : -1; } +/* Return 0 on success, non-zero if an error occurs. */ -static void +static int print_dir_entry(struct de *de) { - char size[64], mod[64], href[PATH_MAX]; + size_t hrefsize; + char *href; + char size[64], mod[64]; struct tm *tm; + hrefsize = PATH_MAX * 3; /* worst case */ + href = (char *)mg_malloc(hrefsize); + if (href == NULL) { + return -1; + } if (de->file.is_directory) { mg_snprintf(de->conn, NULL, /* Buffer is big enough */ @@ -6087,18 +8332,19 @@ print_dir_entry(struct de *de) mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod)); mod[sizeof(mod) - 1] = '\0'; } - mg_url_encode(de->file_name, href, sizeof(href)); - de->conn->num_bytes_sent += - mg_printf(de->conn, - "%s%s" - " %s  %s\n", - de->conn->request_info.local_uri, - href, - de->file.is_directory ? "/" : "", - de->file_name, - de->file.is_directory ? "/" : "", - mod, - size); + mg_url_encode(de->file_name, href, hrefsize); + mg_printf(de->conn, + "%s%s" + " %s  %s\n", + de->conn->request_info.local_uri, + href, + de->file.is_directory ? "/" : "", + de->file_name, + de->file.is_directory ? "/" : "", + mod, + size); + mg_free(href); + return 0; } @@ -6125,9 +8371,9 @@ compare_dir_entries(const void *p1, const void *p2) } else if (*query_string == 'n') { cmp_result = strcmp(a->file_name, b->file_name); } else if (*query_string == 's') { - cmp_result = a->file.size == b->file.size + cmp_result = (a->file.size == b->file.size) ? 0 - : a->file.size > b->file.size ? 1 : -1; + : ((a->file.size > b->file.size) ? 1 : -1); } else if (*query_string == 'd') { cmp_result = (a->file.last_modified == b->file.last_modified) @@ -6136,7 +8382,7 @@ compare_dir_entries(const void *p1, const void *p2) : -1); } - return query_string[1] == 'd' ? -cmp_result : cmp_result; + return (query_string[1] == 'd') ? -cmp_result : cmp_result; } return 0; } @@ -6148,9 +8394,9 @@ must_hide_file(struct mg_connection *conn, const char *path) if (conn && conn->ctx) { const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$"; const char *pattern = conn->ctx->config[HIDE_FILES]; - return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 - || (pattern != NULL - && match_prefix(pattern, strlen(pattern), path) > 0); + return (match_prefix(pw_pattern, strlen(pw_pattern), path) > 0) + || ((pattern != NULL) + && (match_prefix(pattern, strlen(pattern), path) > 0)); } return 0; } @@ -6160,7 +8406,7 @@ static int scan_directory(struct mg_connection *conn, const char *dir, void *data, - void (*cb)(struct de *, void *)) + int (*cb)(struct de *, void *)) { char path[PATH_MAX]; struct dirent *dp; @@ -6258,20 +8504,16 @@ remove_directory(struct mg_connection *conn, const char *dir) strerror(ERRNO)); ok = 0; } - if (de.file.membuf == NULL) { - /* file is not in memory */ - if (de.file.is_directory) { - if (remove_directory(conn, path) == 0) { - ok = 0; - } - } else { - if (mg_remove(conn, path) == 0) { - ok = 0; - } + + if (de.file.is_directory) { + if (remove_directory(conn, path) == 0) { + ok = 0; } } else { - /* file is in memory. It can not be deleted. */ - ok = 0; + /* This will fail file is the file is in memory */ + if (mg_remove(conn, path) == 0) { + ok = 0; + } } } (void)mg_closedir(dirp); @@ -6303,12 +8545,12 @@ realloc2(void *ptr, size_t size) } -static void +static int dir_scan_callback(struct de *de, void *data) { struct dir_scan_data *dsd = (struct dir_scan_data *)data; - if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) { + if ((dsd->entries == NULL) || (dsd->num_entries >= dsd->arr_size)) { dsd->arr_size *= 2; dsd->entries = (struct de *)realloc2(dsd->entries, @@ -6323,6 +8565,8 @@ dir_scan_callback(struct de *de, void *data) dsd->entries[dsd->num_entries].conn = de->conn; dsd->num_entries++; } + + return 0; } @@ -6336,11 +8580,11 @@ handle_directory_request(struct mg_connection *conn, const char *dir) time_t curtime = time(NULL); if (!scan_directory(conn, dir, &data, dir_scan_callback)) { - send_http_error(conn, - 500, - "Error: Cannot open directory\nopendir(%s): %s", - dir, - strerror(ERRNO)); + mg_send_http_error(conn, + 500, + "Error: Cannot open directory\nopendir(%s): %s", + dir, + strerror(ERRNO)); return; } @@ -6350,45 +8594,43 @@ handle_directory_request(struct mg_connection *conn, const char *dir) return; } - sort_direction = conn->request_info.query_string != NULL - && conn->request_info.query_string[1] == 'd' + sort_direction = ((conn->request_info.query_string != NULL) + && (conn->request_info.query_string[1] == 'd')) ? 'a' : 'd'; conn->must_close = 1; mg_printf(conn, "HTTP/1.1 200 OK\r\n"); send_static_cache_header(conn); + send_additional_header(conn); mg_printf(conn, "Date: %s\r\n" "Connection: close\r\n" "Content-Type: text/html; charset=utf-8\r\n\r\n", date); - - conn->num_bytes_sent += - mg_printf(conn, - "Index of %s" - "" - "

Index of %s

"
-	              ""
-	              ""
-	              ""
-	              "",
-	              conn->request_info.local_uri,
-	              conn->request_info.local_uri,
-	              sort_direction,
-	              sort_direction,
-	              sort_direction);
+	mg_printf(conn,
+	          "Index of %s"
+	          ""
+	          "

Index of %s

NameModifiedSize

" + "" + "" + "" + "", + conn->request_info.local_uri, + conn->request_info.local_uri, + sort_direction, + sort_direction, + sort_direction); /* Print first entry - link to a parent directory */ - conn->num_bytes_sent += - mg_printf(conn, - "" - "\n", - conn->request_info.local_uri, - "..", - "Parent directory", - "-", - "-"); + mg_printf(conn, + "" + "\n", + conn->request_info.local_uri, + "..", + "Parent directory", + "-", + "-"); /* Sort and print directory entries */ if (data.entries != NULL) { @@ -6403,7 +8645,7 @@ handle_directory_request(struct mg_connection *conn, const char *dir) mg_free(data.entries); } - conn->num_bytes_sent += mg_printf(conn, "%s", "
NameModifiedSize

%s %s  %s
%s %s  %s
"); + mg_printf(conn, "%s", ""); conn->status_code = 200; } @@ -6411,7 +8653,7 @@ handle_directory_request(struct mg_connection *conn, const char *dir) /* Send len bytes from the opened file to the client. */ static void send_file_data(struct mg_connection *conn, - struct file *filep, + struct mg_file *filep, int64_t offset, int64_t len) { @@ -6424,23 +8666,26 @@ send_file_data(struct mg_connection *conn, } /* Sanity check the offset */ - size = filep->size > INT64_MAX ? INT64_MAX : (int64_t)(filep->size); - offset = offset < 0 ? 0 : offset > size ? size : offset; + size = (filep->stat.size > INT64_MAX) ? INT64_MAX + : (int64_t)(filep->stat.size); + offset = (offset < 0) ? 0 : ((offset > size) ? size : offset); - if (len > 0 && filep->membuf != NULL && size > 0) { + if ((len > 0) && (filep->access.membuf != NULL) && (size > 0)) { /* file stored in memory */ if (len > size - offset) { len = size - offset; } - mg_write(conn, filep->membuf + offset, (size_t)len); - } else if (len > 0 && filep->fp != NULL) { + mg_write(conn, filep->access.membuf + offset, (size_t)len); + } else if (len > 0 && filep->access.fp != NULL) { /* file stored on disk */ #if defined(__linux__) /* sendfile is only available for Linux */ - if (conn->throttle == 0 && conn->ssl == 0) { + if ((conn->ssl == 0) && (conn->throttle == 0) + && (!mg_strcasecmp(conn->ctx->config[ALLOW_SENDFILE_CALL], + "yes"))) { off_t sf_offs = (off_t)offset; ssize_t sf_sent; - int sf_file = fileno(filep->fp); + int sf_file = fileno(filep->access.fp); int loop_cnt = 0; do { @@ -6451,7 +8696,6 @@ send_file_data(struct mg_connection *conn, sf_sent = sendfile(conn->client.sock, sf_file, &sf_offs, sf_tosend); if (sf_sent > 0) { - conn->num_bytes_sent += sf_sent; len -= sf_sent; offset += sf_sent; } else if (loop_cnt == 0) { @@ -6478,9 +8722,9 @@ send_file_data(struct mg_connection *conn, offset = (int64_t)sf_offs; } #endif - if ((offset > 0) && (fseeko(filep->fp, offset, SEEK_SET) != 0)) { + if ((offset > 0) && (fseeko(filep->access.fp, offset, SEEK_SET) != 0)) { mg_cry(conn, "%s: fseeko() failed: %s", __func__, strerror(ERRNO)); - send_http_error( + mg_send_http_error( conn, 500, "%s", @@ -6494,7 +8738,8 @@ send_file_data(struct mg_connection *conn, } /* Read from file, exit the loop on error */ - if ((num_read = (int)fread(buf, 1, (size_t)to_read, filep->fp)) + if ((num_read = + (int)fread(buf, 1, (size_t)to_read, filep->access.fp)) <= 0) { break; } @@ -6506,7 +8751,6 @@ send_file_data(struct mg_connection *conn, } /* Both read and were successful, adjust counters */ - conn->num_bytes_sent += num_written; len -= num_written; } } @@ -6522,22 +8766,22 @@ parse_range_header(const char *header, int64_t *a, int64_t *b) static void -construct_etag(char *buf, size_t buf_len, const struct file *filep) +construct_etag(char *buf, size_t buf_len, const struct mg_file_stat *filestat) { - if (filep != NULL && buf != NULL) { + if ((filestat != NULL) && (buf != NULL)) { mg_snprintf(NULL, NULL, /* All calls to construct_etag use 64 byte buffer */ buf, buf_len, "\"%lx.%" INT64_FMT "\"", - (unsigned long)filep->last_modified, - filep->size); + (unsigned long)filestat->last_modified, + filestat->size); } } static void -fclose_on_exec(struct file *filep, struct mg_connection *conn) +fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn) { if (filep != NULL && filep->fp != NULL) { #ifdef _WIN32 @@ -6557,8 +8801,9 @@ fclose_on_exec(struct file *filep, struct mg_connection *conn) static void handle_static_file_request(struct mg_connection *conn, const char *path, - struct file *filep, - const char *mime_type) + struct mg_file *filep, + const char *mime_type, + const char *additional_headers) { char date[64], lm[64], etag[64]; char range[128]; /* large enough, so there will be no overflow */ @@ -6570,8 +8815,9 @@ handle_static_file_request(struct mg_connection *conn, char gz_path[PATH_MAX]; const char *encoding = ""; const char *cors1, *cors2, *cors3; + int allow_on_the_fly_compression; - if (conn == NULL || conn->ctx == NULL || filep == NULL) { + if ((conn == NULL) || (conn->ctx == NULL) || (filep == NULL)) { return; } @@ -6581,63 +8827,70 @@ handle_static_file_request(struct mg_connection *conn, mime_vec.ptr = mime_type; mime_vec.len = strlen(mime_type); } - if (filep->size > INT64_MAX) { - send_http_error(conn, - 500, - "Error: File size is too large to send\n%" INT64_FMT, - filep->size); + if (filep->stat.size > INT64_MAX) { + mg_send_http_error(conn, + 500, + "Error: File size is too large to send\n%" INT64_FMT, + filep->stat.size); + return; } - cl = (int64_t)filep->size; + cl = (int64_t)filep->stat.size; conn->status_code = 200; range[0] = '\0'; /* if this file is in fact a pre-gzipped file, rewrite its filename * it's important to rewrite the filename after resolving * the mime type from it, to preserve the actual file's type */ - if (filep->gzipped) { + allow_on_the_fly_compression = conn->accept_gzip; + + if (filep->stat.is_gzipped) { mg_snprintf(conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", path); if (truncated) { - send_http_error(conn, - 500, - "Error: Path of zipped file too long (%s)", - path); + mg_send_http_error(conn, + 500, + "Error: Path of zipped file too long (%s)", + path); return; } path = gz_path; encoding = "Content-Encoding: gzip\r\n"; + + /* File is already compressed. No "on the fly" compression. */ + allow_on_the_fly_compression = 0; } - if (!mg_fopen(conn, path, "rb", filep)) { - send_http_error(conn, - 500, - "Error: Cannot open file\nfopen(%s): %s", - path, - strerror(ERRNO)); + if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) { + mg_send_http_error(conn, + 500, + "Error: Cannot open file\nfopen(%s): %s", + path, + strerror(ERRNO)); return; } - fclose_on_exec(filep, conn); + fclose_on_exec(&filep->access, conn); /* If Range: header specified, act accordingly */ r1 = r2 = 0; hdr = mg_get_header(conn, "Range"); - if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 && r1 >= 0 - && r2 >= 0) { + if ((hdr != NULL) && ((n = parse_range_header(hdr, &r1, &r2)) > 0) + && (r1 >= 0) && (r2 >= 0)) { /* actually, range requests don't play well with a pre-gzipped * file (since the range is specified in the uncompressed space) */ - if (filep->gzipped) { - send_http_error( + if (filep->stat.is_gzipped) { + mg_send_http_error( conn, - 501, + 416, /* 416 = Range Not Satisfiable */ "%s", "Error: Range requests in gzipped files are not supported"); - mg_fclose(filep); + (void)mg_fclose( + &filep->access); /* ignore error on read only file */ return; } conn->status_code = 206; - cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1 : cl - r1; + cl = (n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1); mg_snprintf(conn, NULL, /* range buffer is big enough */ range, @@ -6646,15 +8899,19 @@ handle_static_file_request(struct mg_connection *conn, "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n", r1, r1 + cl - 1, - filep->size); + filep->stat.size); msg = "Partial Content"; + + /* Do not compress ranges. */ + allow_on_the_fly_compression = 0; } hdr = mg_get_header(conn, "Origin"); if (hdr) { /* Cross-origin resource sharing (CORS), see * http://www.html5rocks.com/en/tutorials/cors/, - * http://www.html5rocks.com/static/images/cors_server_flowchart.png - + * http://www.html5rocks.com/static/images/cors_server_flowchart.png + * - * preflight is not supported for files. */ cors1 = "Access-Control-Allow-Origin: "; cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN]; @@ -6663,12 +8920,25 @@ handle_static_file_request(struct mg_connection *conn, cors1 = cors2 = cors3 = ""; } - /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to + /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, + * according to * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */ gmt_time_string(date, sizeof(date), &curtime); - gmt_time_string(lm, sizeof(lm), &filep->last_modified); - construct_etag(etag, sizeof(etag), filep); + gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified); + construct_etag(etag, sizeof(etag), &filep->stat); + /* On the fly compression allowed */ + if (allow_on_the_fly_compression) { + ; + /* TODO: add interface to compression module */ + /* e.g., def from https://zlib.net/zlib_how.html */ + /* Check license (zlib has a permissive license, but */ + /* is still not MIT) and use dynamic binding like */ + /* done with OpenSSL */ + /* See #199 (https://github.com/civetweb/civetweb/issues/199) */ + } + + /* Send header */ (void)mg_printf(conn, "HTTP/1.1 %d %s\r\n" "%s%s%s" @@ -6680,6 +8950,8 @@ handle_static_file_request(struct mg_connection *conn, cors3, date); send_static_cache_header(conn); + send_additional_header(conn); + (void)mg_printf(conn, "Last-Modified: %s\r\n" "Etag: %s\r\n" @@ -6687,7 +8959,7 @@ handle_static_file_request(struct mg_connection *conn, "Content-Length: %" INT64_FMT "\r\n" "Connection: %s\r\n" "Accept-Ranges: bytes\r\n" - "%s%s\r\n", + "%s%s", lm, etag, (int)mime_vec.len, @@ -6697,13 +8969,61 @@ handle_static_file_request(struct mg_connection *conn, range, encoding); + /* The previous code must not add any header starting with X- to make + * sure no one of the additional_headers is included twice */ + + if (additional_headers != NULL) { + (void)mg_printf(conn, + "%.*s\r\n\r\n", + (int)strlen(additional_headers), + additional_headers); + } else { + (void)mg_printf(conn, "\r\n"); + } + if (strcmp(conn->request_info.request_method, "HEAD") != 0) { send_file_data(conn, filep, r1, cl); } - mg_fclose(filep); + (void)mg_fclose(&filep->access); /* ignore error on read only file */ } +#if !defined(NO_CACHING) +static void +handle_not_modified_static_file_request(struct mg_connection *conn, + struct mg_file *filep) +{ + char date[64], lm[64], etag[64]; + time_t curtime = time(NULL); + + if ((conn == NULL) || (filep == NULL)) { + return; + } + conn->status_code = 304; + gmt_time_string(date, sizeof(date), &curtime); + gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified); + construct_etag(etag, sizeof(etag), &filep->stat); + + (void)mg_printf(conn, + "HTTP/1.1 %d %s\r\n" + "Date: %s\r\n", + conn->status_code, + mg_get_response_code_text(conn, conn->status_code), + date); + send_static_cache_header(conn); + send_additional_header(conn); + (void)mg_printf(conn, + "Last-Modified: %s\r\n" + "Etag: %s\r\n" + "Connection: %s\r\n" + "\r\n", + lm, + etag, + suggest_connection_header(conn)); +} +#endif + + void mg_send_file(struct mg_connection *conn, const char *path) { @@ -6716,26 +9036,40 @@ mg_send_mime_file(struct mg_connection *conn, const char *path, const char *mime_type) { - struct file file = STRUCT_FILE_INITIALIZER; - if (mg_stat(conn, path, &file)) { - if (file.is_directory) { - if (!conn) { - return; - } + mg_send_mime_file2(conn, path, mime_type, NULL); +} + + +void +mg_send_mime_file2(struct mg_connection *conn, + const char *path, + const char *mime_type, + const char *additional_headers) +{ + struct mg_file file = STRUCT_FILE_INITIALIZER; + + if (!conn) { + /* No conn */ + return; + } + + if (mg_stat(conn, path, &file.stat)) { + if (file.stat.is_directory) { if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) { handle_directory_request(conn, path); } else { - send_http_error(conn, - 403, - "%s", - "Error: Directory listing denied"); + mg_send_http_error(conn, + 403, + "%s", + "Error: Directory listing denied"); } } else { - handle_static_file_request(conn, path, &file, mime_type); + handle_static_file_request( + conn, path, &file, mime_type, additional_headers); } } else { - send_http_error(conn, 404, "%s", "Error: File not found"); + mg_send_http_error(conn, 404, "%s", "Error: File not found"); } } @@ -6751,7 +9085,7 @@ put_dir(struct mg_connection *conn, const char *path) { char buf[PATH_MAX]; const char *s, *p; - struct file file = STRUCT_FILE_INITIALIZER; + struct mg_file file = STRUCT_FILE_INITIALIZER; size_t len; int res = 1; @@ -6767,7 +9101,7 @@ put_dir(struct mg_connection *conn, const char *path) /* Try to create intermediate directory */ DEBUG_TRACE("mkdir(%s)", buf); - if (!mg_stat(conn, buf, &file) && mg_mkdir(conn, buf, 0755) != 0) { + if (!mg_stat(conn, buf, &file.stat) && mg_mkdir(conn, buf, 0755) != 0) { /* path does not exixt and can not be created */ res = -2; break; @@ -6799,7 +9133,7 @@ mg_store_body(struct mg_connection *conn, const char *path) char buf[MG_BUF_LEN]; long long len = 0; int ret, n; - struct file fi; + struct mg_file fi; if (conn->consumed_content != 0) { mg_cry(conn, "%s: Contents already consumed", __func__); @@ -6817,24 +9151,27 @@ mg_store_body(struct mg_connection *conn, const char *path) return 0; } - if (mg_fopen(conn, path, "w", &fi) == 0) { + if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fi) == 0) { return -12; } ret = mg_read(conn, buf, sizeof(buf)); while (ret > 0) { - n = (int)fwrite(buf, 1, (size_t)ret, fi.fp); + n = (int)fwrite(buf, 1, (size_t)ret, fi.access.fp); if (n != ret) { - mg_fclose(&fi); + (void)mg_fclose( + &fi.access); /* File is bad and will be removed anyway. */ remove_bad_file(conn, path); return -13; } + len += ret; ret = mg_read(conn, buf, sizeof(buf)); } - /* TODO: mg_fclose should return an error, - * and every caller should check and handle it. */ - if (fclose(fi.fp) != 0) { + /* File is open for writing. If fclose fails, there was probably an + * error flushing the buffer to disk, so the file on disk might be + * broken. Delete it and return an error to the caller. */ + if (mg_fclose(&fi.access) != 0) { remove_bad_file(conn, path); return -14; } @@ -6843,51 +9180,91 @@ mg_store_body(struct mg_connection *conn, const char *path) } -/* Parse HTTP headers from the given buffer, advance buffer to the point - * where parsing stopped. */ -static void -parse_http_headers(char **buf, struct mg_request_info *ri) +/* Parse a buffer: + * Forward the string pointer till the end of a word, then + * terminate it and forward till the begin of the next word. + */ +static int +skip_to_end_of_word_and_terminate(char **ppw, int eol) { - int i; - - if (!ri) { - return; + /* Forward until a space is found - use isgraph here */ + /* See http://www.cplusplus.com/reference/cctype/ */ + while (isgraph(**ppw)) { + (*ppw)++; } - ri->num_headers = 0; + /* Check end of word */ + if (eol) { + /* must be a end of line */ + if ((**ppw != '\r') && (**ppw != '\n')) { + return -1; + } + } else { + /* must be a end of a word, but not a line */ + if (**ppw != ' ') { + return -1; + } + } - for (i = 0; i < (int)ARRAY_SIZE(ri->http_headers); i++) { + /* Terminate and forward to the next word */ + do { + **ppw = 0; + (*ppw)++; + } while ((**ppw) && isspace(**ppw)); + + /* Check after term */ + if (!eol) { + /* if it's not the end of line, there must be a next word */ + if (!isgraph(**ppw)) { + return -1; + } + } + + /* ok */ + return 1; +} + + +/* Parse HTTP headers from the given buffer, advance buf pointer + * to the point where parsing stopped. + * All parameters must be valid pointers (not NULL). + * Return <0 on error. */ +static int +parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS]) +{ + int i; + int num_headers = 0; + + for (i = 0; i < (int)MG_MAX_HEADERS; i++) { char *dp = *buf; - while ((*dp != ':') && (*dp != '\r') && (*dp != 0)) { + while ((*dp != ':') && (*dp >= 33) && (*dp <= 126)) { dp++; } - if (!*dp) { - /* neither : nor \r\n. This is not a valid field. */ + if (dp == *buf) { + /* End of headers reached. */ break; } - if (*dp == '\r') { - if (dp[1] == '\n') { - /* \r\n */ - ri->http_headers[i].name = *buf; - ri->http_headers[i].value = 0; - *buf = dp; - } else { - /* stray \r. This is not valid. */ - break; - } - } else { - /* (*dp == ':') */ - *dp = 0; - ri->http_headers[i].name = *buf; - do { - dp++; - } while (*dp == ' '); - - ri->http_headers[i].value = dp; - *buf = strstr(dp, "\r\n"); + if (*dp != ':') { + /* This is not a valid field. */ + return -1; } - ri->num_headers = i + 1; + /* End of header key (*dp == ':') */ + /* Truncate here and set the key name */ + *dp = 0; + hdr[i].name = *buf; + do { + dp++; + } while (*dp == ' '); + + /* The rest of the line is the value */ + hdr[i].value = dp; + *buf = dp + strcspn(dp, "\r\n"); + if (((*buf)[0] != '\r') || ((*buf)[1] != '\n')) { + *buf = NULL; + } + + num_headers = i + 1; if (*buf) { (*buf)[0] = 0; (*buf)[1] = 0; @@ -6897,92 +9274,309 @@ parse_http_headers(char **buf, struct mg_request_info *ri) break; } - if (*buf[0] == '\r') { + if ((*buf)[0] == '\r') { /* This is the end of the header */ break; } } + return num_headers; +} + + +struct mg_http_method_info { + const char *name; + int request_has_body; + int response_has_body; + int is_safe; + int is_idempotent; + int is_cacheable; +}; + + +/* https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods */ +static struct mg_http_method_info http_methods[] = { + /* HTTP (RFC 2616) */ + {"GET", 0, 1, 1, 1, 1}, + {"POST", 1, 1, 0, 0, 0}, + {"PUT", 1, 0, 0, 1, 0}, + {"DELETE", 0, 0, 0, 1, 0}, + {"HEAD", 0, 0, 1, 1, 1}, + {"OPTIONS", 0, 0, 1, 1, 0}, + {"CONNECT", 1, 1, 0, 0, 0}, + /* TRACE method (RFC 2616) is not supported for security reasons */ + + /* PATCH method (RFC 5789) */ + {"PATCH", 1, 0, 0, 0, 0}, + /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */ + + /* WEBDAV (RFC 2518) */ + {"PROPFIND", 0, 1, 1, 1, 0}, + /* http://www.webdav.org/specs/rfc4918.html, 9.1: + * Some PROPFIND results MAY be cached, with care, + * as there is no cache validation mechanism for + * most properties. This method is both safe and + * idempotent (see Section 9.1 of [RFC2616]). */ + {"MKCOL", 0, 0, 0, 1, 0}, + /* http://www.webdav.org/specs/rfc4918.html, 9.1: + * When MKCOL is invoked without a request body, + * the newly created collection SHOULD have no + * members. A MKCOL request message may contain + * a message body. The precise behavior of a MKCOL + * request when the body is present is undefined, + * ... ==> We do not support MKCOL with body data. + * This method is idempotent, but not safe (see + * Section 9.1 of [RFC2616]). Responses to this + * method MUST NOT be cached. */ + + /* Unsupported WEBDAV Methods: */ + /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */ + /* + 11 methods from RFC 3253 */ + /* ORDERPATCH (RFC 3648) */ + /* ACL (RFC 3744) */ + /* SEARCH (RFC 5323) */ + /* + MicroSoft extensions + * https://msdn.microsoft.com/en-us/library/aa142917.aspx */ + + /* REPORT method (RFC 3253) */ + {"REPORT", 1, 1, 1, 1, 1}, + /* REPORT method only allowed for CGI/Lua/LSP and callbacks. */ + /* It was defined for WEBDAV in RFC 3253, Sec. 3.6 + * (https://tools.ietf.org/html/rfc3253#section-3.6), but seems + * to be useful for REST in case a "GET request with body" is + * required. */ + + {NULL, 0, 0, 0, 0, 0} + /* end of list */ +}; + + +static const struct mg_http_method_info * +get_http_method_info(const char *method) +{ + /* Check if the method is known to the server. The list of all known + * HTTP methods can be found here at + * http://www.iana.org/assignments/http-methods/http-methods.xhtml + */ + const struct mg_http_method_info *m = http_methods; + + while (m->name) { + if (!strcmp(m->name, method)) { + return m; + } + m++; + } + return m; } static int is_valid_http_method(const char *method) { - return !strcmp(method, "GET") /* HTTP (RFC 2616) */ - || !strcmp(method, "POST") /* HTTP (RFC 2616) */ - || !strcmp(method, "HEAD") /* HTTP (RFC 2616) */ - || !strcmp(method, "PUT") /* HTTP (RFC 2616) */ - || !strcmp(method, "DELETE") /* HTTP (RFC 2616) */ - || !strcmp(method, "OPTIONS") /* HTTP (RFC 2616) */ - /* TRACE method (RFC 2616) is not supported for security reasons */ - || !strcmp(method, "CONNECT") /* HTTP (RFC 2616) */ - - || !strcmp(method, "PROPFIND") /* WEBDAV (RFC 2518) */ - || !strcmp(method, "MKCOL") /* WEBDAV (RFC 2518) */ - - /* Unsupported WEBDAV Methods: */ - /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */ - /* + 11 methods from RFC 3253 */ - /* ORDERPATCH (RFC 3648) */ - /* ACL (RFC 3744) */ - /* SEARCH (RFC 5323) */ - /* + MicroSoft extensions - * https://msdn.microsoft.com/en-us/library/aa142917.aspx */ - - /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */ - || !strcmp(method, "PATCH"); /* PATCH method (RFC 5789) */ + return (get_http_method_info(method) != NULL); } /* Parse HTTP request, fill in mg_request_info structure. * This function modifies the buffer by NUL-terminating - * HTTP request components, header names and header values. */ + * HTTP request components, header names and header values. + * Parameters: + * buf (in/out): pointer to the HTTP header to parse and split + * len (in): length of HTTP header buffer + * re (out): parsed header as mg_request_info + * buf and ri must be valid pointers (not NULL), len>0. + * Returns <0 on error. */ static int -parse_http_message(int check_method, - char *buf, - int len, - struct mg_request_info *ri) +parse_http_request(int check_method, char *buf, int len, struct mg_request_info *ri) { - int is_request, request_length; + int request_length; + int init_skip = 0; - if (!ri) { + /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr, + * remote_port */ + ri->remote_user = ri->request_method = ri->request_uri = ri->http_version = + NULL; + ri->num_headers = 0; + + /* RFC says that all initial whitespaces should be ingored */ + /* This included all leading \r and \n (isspace) */ + /* See table: http://www.cplusplus.com/reference/cctype/ */ + while ((len > 0) && isspace(*(unsigned char *)buf)) { + buf++; + len--; + init_skip++; + } + + if (len == 0) { + /* Incomplete request */ return 0; } - request_length = get_request_len(buf, len); - - if (request_length > 0) { - /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr, - * remote_port */ - ri->remote_user = ri->request_method = ri->request_uri = - ri->http_version = NULL; - ri->num_headers = 0; - - buf[request_length - 1] = '\0'; - - /* RFC says that all initial whitespaces should be ingored */ - while (*buf != '\0' && isspace(*(unsigned char *)buf)) { - buf++; - } - ri->request_method = skip(&buf, " "); - ri->request_uri = skip(&buf, " "); - ri->http_version = skip(&buf, "\r\n"); - - /* HTTP message could be either HTTP request or HTTP response, e.g. - * "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." */ - is_request = - check_method ? is_valid_http_method(ri->request_method) : 1; - if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) - || (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) { - request_length = -1; - } else { - if (is_request) { - ri->http_version += 5; - } - parse_http_headers(&buf, ri); - } + /* Control characters are not allowed, including zero */ + if (iscntrl(*(unsigned char *)buf)) { + return -1; } - return request_length; + + /* Find end of HTTP header */ + request_length = get_http_header_len(buf, len); + if (request_length <= 0) { + return request_length; + } + buf[request_length - 1] = '\0'; + + if ((*buf == 0) || (*buf == '\r') || (*buf == '\n')) { + return -1; + } + + /* The first word has to be the HTTP method */ + ri->request_method = buf; + + if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) { + return -1; + } + + /* Check for a valid http method */ + if (check_method && !is_valid_http_method(ri->request_method)) { + return -1; + } + + /* The second word is the URI */ + ri->request_uri = skip_quoted(&buf, " ", " ", 0); + + /* Next would be the HTTP version */ + ri->http_version = buf; + + if (skip_to_end_of_word_and_terminate(&buf, 1) <= 0) { + return -1; + } + + /* Check for a valid HTTP version key */ + if (strncmp(ri->http_version, "HTTP/", 5) != 0) { + /* Invalid request */ + return -1; + } + ri->http_version += 5; + + + /* Parse all HTTP headers */ + ri->num_headers = parse_http_headers(&buf, ri->http_headers); + if (ri->num_headers < 0) { + /* Error while parsing headers */ + return -1; + } + + return request_length + init_skip; +} + + +static int +parse_http_response(char *buf, int len, struct mg_response_info *ri) +{ + int response_length; + int init_skip = 0; + char *tmp, *tmp2; + long l; + + /* Initialize elements. */ + ri->http_version = ri->status_text = NULL; + ri->num_headers = ri->status_code = 0; + + /* RFC says that all initial whitespaces should be ingored */ + /* This included all leading \r and \n (isspace) */ + /* See table: http://www.cplusplus.com/reference/cctype/ */ + while ((len > 0) && isspace(*(unsigned char *)buf)) { + buf++; + len--; + init_skip++; + } + + if (len == 0) { + /* Incomplete request */ + return 0; + } + + /* Control characters are not allowed, including zero */ + if (iscntrl(*(unsigned char *)buf)) { + return -1; + } + + /* Find end of HTTP header */ + response_length = get_http_header_len(buf, len); + if (response_length <= 0) { + return response_length; + } + buf[response_length - 1] = '\0'; + + + /* TODO: Define mg_response_info and implement parsing */ + (void)buf; + (void)len; + (void)ri; + + /* RFC says that all initial whitespaces should be ingored */ + while ((*buf != '\0') && isspace(*(unsigned char *)buf)) { + buf++; + } + if ((*buf == 0) || (*buf == '\r') || (*buf == '\n')) { + return -1; + } + + /* The first word is the HTTP version */ + /* Check for a valid HTTP version key */ + if (strncmp(buf, "HTTP/", 5) != 0) { + /* Invalid request */ + return -1; + } + buf += 5; + if (!isgraph(buf[0])) { + /* Invalid request */ + return -1; + } + ri->http_version = buf; + + if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) { + return -1; + } + + /* The second word is the status as a number */ + tmp = buf; + + if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) { + return -1; + } + + l = strtol(tmp, &tmp2, 10); + if ((l < 100) || (l >= 1000) || ((tmp2 - tmp) != 3) || (*tmp2 != 0)) { + /* Everything else but a 3 digit code is invalid */ + return -1; + } + ri->status_code = (int)l; + + /* The rest of the line is the status text */ + ri->status_text = buf; + + /* Find end of status text */ + /* isgraph or isspace = isprint */ + while (isprint(*buf)) { + buf++; + } + if ((*buf != '\r') && (*buf != '\n')) { + return -1; + } + /* Terminate string and forward buf to next line */ + do { + *buf = 0; + buf++; + } while ((*buf) && isspace(*buf)); + + + /* Parse all HTTP headers */ + ri->num_headers = parse_http_headers(&buf, ri->http_headers); + if (ri->num_headers < 0) { + /* Error while parsing headers */ + return -1; + } + + return response_length + init_skip; } @@ -6992,7 +9586,7 @@ parse_http_message(int check_method, * have some data. The length of the data is stored in nread. * Upon every read operation, increase nread by the number of bytes read. */ static int -read_request(FILE *fp, +read_message(FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, @@ -7014,103 +9608,71 @@ read_request(FILE *fp, } else { request_timeout = -1.0; } + if (conn->handled_requests > 0) { + if (conn->ctx->config[KEEP_ALIVE_TIMEOUT]) { + request_timeout = + atof(conn->ctx->config[KEEP_ALIVE_TIMEOUT]) / 1000.0; + } + } - request_len = get_request_len(buf, *nread); + request_len = get_http_header_len(buf, *nread); /* first time reading from this connection */ clock_gettime(CLOCK_MONOTONIC, &last_action_time); - while ( - (conn->ctx->stop_flag == 0) && (*nread < bufsiz) && (request_len == 0) - && ((mg_difftimespec(&last_action_time, &(conn->req_time)) - <= request_timeout) || (request_timeout < 0)) - && ((n = pull(fp, conn, buf + *nread, bufsiz - *nread, request_timeout)) - > 0)) { - *nread += n; - /* assert(*nread <= bufsiz); */ - if (*nread > bufsiz) { + while (request_len == 0) { + /* Full request not yet received */ + if (conn->ctx->stop_flag != 0) { + /* Server is to be stopped. */ + return -1; + } + + if (*nread >= bufsiz) { + /* Request too long */ return -2; } - request_len = get_request_len(buf, *nread); - if (request_timeout > 0.0) { + + n = pull_inner( + fp, conn, buf + *nread, bufsiz - *nread, request_timeout); + if (n == -2) { + /* Receive error */ + return -1; + } + if (n > 0) { + *nread += n; + request_len = get_http_header_len(buf, *nread); + } else { + request_len = 0; + } + + if ((request_len == 0) && (request_timeout >= 0)) { + if (mg_difftimespec(&last_action_time, &(conn->req_time)) + > request_timeout) { + /* Timeout */ + return -1; + } clock_gettime(CLOCK_MONOTONIC, &last_action_time); } } - return (request_len <= 0 && n <= 0) ? -1 : request_len; + return request_len; } -#if !defined(NO_FILES) -/* For given directory path, substitute it to valid index file. - * Return 1 if index file has been found, 0 if not found. - * If the file is found, it's stats is returned in stp. */ -static int -substitute_index_file(struct mg_connection *conn, - char *path, - size_t path_len, - struct file *filep) -{ - if (conn && conn->ctx) { - const char *list = conn->ctx->config[INDEX_FILES]; - struct file file = STRUCT_FILE_INITIALIZER; - struct vec filename_vec; - size_t n = strlen(path); - int found = 0; - - /* The 'path' given to us points to the directory. Remove all trailing - * directory separator characters from the end of the path, and - * then append single directory separator character. */ - while (n > 0 && path[n - 1] == '/') { - n--; - } - path[n] = '/'; - - /* Traverse index files list. For each entry, append it to the given - * path and see if the file exists. If it exists, break the loop */ - while ((list = next_option(list, &filename_vec, NULL)) != NULL) { - /* Ignore too long entries that may overflow path buffer */ - if (filename_vec.len > path_len - (n + 2)) { - continue; - } - - /* Prepare full path to the index file */ - mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1); - - /* Does it exist? */ - if (mg_stat(conn, path, &file)) { - /* Yes it does, break the loop */ - *filep = file; - found = 1; - break; - } - } - - /* If no index file exists, restore directory path */ - if (!found) { - path[n] = '\0'; - } - - return found; - } - return 0; -} -#endif - #if !defined(NO_CACHING) /* Return True if we should reply 304 Not Modified. */ static int -is_not_modified(const struct mg_connection *conn, const struct file *filep) +is_not_modified(const struct mg_connection *conn, + const struct mg_file_stat *filestat) { char etag[64]; const char *ims = mg_get_header(conn, "If-Modified-Since"); const char *inm = mg_get_header(conn, "If-None-Match"); - construct_etag(etag, sizeof(etag), filep); - if (!filep) { - return 0; - } - return (inm != NULL && !mg_strcasecmp(etag, inm)) - || (ims != NULL && (filep->last_modified <= parse_date_string(ims))); + construct_etag(etag, sizeof(etag), filestat); + + return ((inm != NULL) && !mg_strcasecmp(etag, inm)) + || ((ims != NULL) + && (filestat->last_modified <= parse_date_string(ims))); } #endif /* !NO_CACHING */ @@ -7135,23 +9697,24 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl) expect = mg_get_header(conn, "Expect"); /* assert(fp != NULL); */ if (!fp) { - send_http_error(conn, 500, "%s", "Error: NULL File"); + mg_send_http_error(conn, 500, "%s", "Error: NULL File"); return 0; } - if (conn->content_len == -1 && !conn->is_chunked) { + if ((conn->content_len == -1) && (!conn->is_chunked)) { /* Content length is not specified by the client. */ - send_http_error(conn, - 411, - "%s", - "Error: Client did not specify content length"); + mg_send_http_error(conn, + 411, + "%s", + "Error: Client did not specify content length"); } else if ((expect != NULL) && (mg_strcasecmp(expect, "100-continue") != 0)) { - /* Client sent an "Expect: xyz" header and xyz is not 100-continue. */ - send_http_error(conn, - 417, - "Error: Can not fulfill expectation %s", - expect); + /* Client sent an "Expect: xyz" header and xyz is not 100-continue. + */ + mg_send_http_error(conn, + 417, + "Error: Can not fulfill expectation %s", + expect); } else { if (expect != NULL) { (void)mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n"); @@ -7167,7 +9730,7 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl) /* assert(conn->consumed_content == 0); */ if ((buffered_len < 0) || (conn->consumed_content != 0)) { - send_http_error(conn, 500, "%s", "Error: Size mismatch"); + mg_send_http_error(conn, 500, "%s", "Error: Size mismatch"); return 0; } @@ -7186,11 +9749,16 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl) if ((int64_t)to_read > conn->content_len - conn->consumed_content) { to_read = (int)(conn->content_len - conn->consumed_content); } - nread = pull(NULL, conn, buf, to_read, timeout); - if (nread <= 0 - || push_all(conn->ctx, fp, sock, ssl, buf, nread) != nread) { + nread = pull_inner(NULL, conn, buf, to_read, timeout); + if (nread == -2) { + /* error */ break; } + if (nread > 0) { + if (push_all(conn->ctx, fp, sock, ssl, buf, nread) != nread) { + break; + } + } conn->consumed_content += nread; } @@ -7203,7 +9771,7 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl) /* NOTE: Maybe some data has already been sent. */ /* TODO (low): If some data has been sent, a correct error * reply can no longer be sent, so just close the connection */ - send_http_error(conn, 500, "%s", ""); + mg_send_http_error(conn, 500, "%s", ""); } } @@ -7212,10 +9780,12 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl) #endif #if !defined(NO_CGI) -/* This structure helps to create an environment for the spawned CGI program. +/* This structure helps to create an environment for the spawned CGI + * program. * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings, * last element must be NULL. - * However, on Windows there is a requirement that all these VARIABLE=VALUE\0 + * However, on Windows there is a requirement that all these + * VARIABLE=VALUE\0 * strings must reside in a contiguous buffer. The end of the buffer is * marked by two '\0' characters. * We satisfy both worlds: we create an envp array (which is vars), all @@ -7243,7 +9813,7 @@ static void addenv(struct cgi_environment *env, const char *fmt, ...) { size_t n, space; - int truncated; + int truncated = 0; char *added; va_list ap; @@ -7257,7 +9827,7 @@ addenv(struct cgi_environment *env, const char *fmt, ...) if (space <= n) { /* Allocate new buffer */ n = env->buflen + CGI_ENVIRONMENT_SIZE; - added = (char *)mg_realloc(env->buf, n); + added = (char *)mg_realloc_ctx(env->buf, n, env->conn->ctx); if (!added) { /* Out of memory */ mg_cry(env->conn, @@ -7306,8 +9876,9 @@ addenv(struct cgi_environment *env, const char *fmt, ...) env->varused++; } +/* Return 0 on success, non-zero if an error occurs. */ -static void +static int prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_environment *env) @@ -7315,19 +9886,32 @@ prepare_cgi_environment(struct mg_connection *conn, const char *s; struct vec var_vec; char *p, src_addr[IP_ADDR_STR_LEN], http_var_name[128]; - int i, truncated; + int i, truncated, uri_len; - if (conn == NULL || prog == NULL || env == NULL) { - return; + if ((conn == NULL) || (prog == NULL) || (env == NULL)) { + return -1; } env->conn = conn; env->buflen = CGI_ENVIRONMENT_SIZE; env->bufused = 0; - env->buf = (char *)mg_malloc(env->buflen); + env->buf = (char *)mg_malloc_ctx(env->buflen, conn->ctx); + if (env->buf == NULL) { + mg_cry(conn, + "%s: Not enough memory for environmental buffer", + __func__); + return -1; + } env->varlen = MAX_CGI_ENVIR_VARS; env->varused = 0; - env->var = (char **)mg_malloc(env->buflen * sizeof(char *)); + env->var = (char **)mg_malloc_ctx(env->buflen * sizeof(char *), conn->ctx); + if (env->var == NULL) { + mg_cry(conn, + "%s: Not enough memory for environmental variables", + __func__); + mg_free(env->buf); + return -1; + } addenv(env, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]); addenv(env, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]); @@ -7358,11 +9942,28 @@ prepare_cgi_environment(struct mg_connection *conn, addenv(env, "LOCAL_URI=%s", conn->request_info.local_uri); /* SCRIPT_NAME */ - addenv(env, - "SCRIPT_NAME=%.*s", - (int)strlen(conn->request_info.local_uri) - - ((conn->path_info == NULL) ? 0 : (int)strlen(conn->path_info)), - conn->request_info.local_uri); + uri_len = (int)strlen(conn->request_info.local_uri); + if (conn->path_info == NULL) { + if (conn->request_info.local_uri[uri_len - 1] != '/') { + /* URI: /path_to_script/script.cgi */ + addenv(env, "SCRIPT_NAME=%s", conn->request_info.local_uri); + } else { + /* URI: /path_to_script/ ... using index.cgi */ + const char *index_file = strrchr(prog, '/'); + if (index_file) { + addenv(env, + "SCRIPT_NAME=%s%s", + conn->request_info.local_uri, + index_file + 1); + } + } + } else { + /* URI: /path_to_script/script.cgi/path_info */ + addenv(env, + "SCRIPT_NAME=%.*s", + uri_len - (int)strlen(conn->path_info), + conn->request_info.local_uri); + } addenv(env, "SCRIPT_FILENAME=%s", prog); if (conn->path_info == NULL) { @@ -7374,7 +9975,7 @@ prepare_cgi_environment(struct mg_connection *conn, conn->path_info); } - addenv(env, "HTTPS=%s", conn->ssl == NULL ? "off" : "on"); + addenv(env, "HTTPS=%s", (conn->ssl == NULL) ? "off" : "on"); if ((s = mg_get_header(conn, "Content-Type")) != NULL) { addenv(env, "CONTENT_TYPE=%s", s); @@ -7468,6 +10069,8 @@ prepare_cgi_environment(struct mg_connection *conn, env->var[env->varused] = NULL; env->buf[env->bufused] = '\0'; + + return 0; } @@ -7483,7 +10086,7 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) struct mg_request_info ri; struct cgi_environment blk; FILE *in = NULL, *out = NULL, *err = NULL; - struct file fout = STRUCT_FILE_INITIALIZER; + struct mg_file fout = STRUCT_FILE_INITIALIZER; pid_t pid = (pid_t)-1; if (conn == NULL) { @@ -7492,7 +10095,12 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) buf = NULL; buflen = 16384; - prepare_cgi_environment(conn, prog, &blk); + i = prepare_cgi_environment(conn, prog, &blk); + if (i != 0) { + blk.buf = NULL; + blk.var = NULL; + goto done; + } /* CGI must be executed in its own directory. 'dir' must point to the * directory containing executable program, 'p' must point to the @@ -7501,27 +10109,32 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) if (truncated) { mg_cry(conn, "Error: CGI program \"%s\": Path too long", prog); - send_http_error(conn, 500, "Error: %s", "CGI path too long"); + mg_send_http_error(conn, 500, "Error: %s", "CGI path too long"); goto done; } if ((p = strrchr(dir, '/')) != NULL) { *p++ = '\0'; } else { - dir[0] = '.', dir[1] = '\0'; + dir[0] = '.'; + dir[1] = '\0'; p = (char *)prog; } - if (pipe(fdin) != 0 || pipe(fdout) != 0 || pipe(fderr) != 0) { + if ((pipe(fdin) != 0) || (pipe(fdout) != 0) || (pipe(fderr) != 0)) { status = strerror(ERRNO); mg_cry(conn, "Error: CGI program \"%s\": Can not create CGI pipes: %s", prog, status); - send_http_error(conn, 500, "Error: Cannot create CGI pipe: %s", status); + mg_send_http_error(conn, + 500, + "Error: Cannot create CGI pipe: %s", + status); goto done; } + DEBUG_TRACE("CGI: spawn %s %s\n", dir, p); pid = spawn_process(conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir); if (pid == (pid_t)-1) { @@ -7530,15 +10143,16 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) "Error: CGI program \"%s\": Can not spawn CGI process: %s", prog, status); - send_http_error(conn, - 500, - "Error: Cannot spawn CGI process [%s]: %s", - prog, - status); + mg_send_http_error(conn, + 500, + "Error: Cannot spawn CGI process [%s]: %s", + prog, + status); goto done; } - /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */ + /* Make sure child closes all pipe descriptors. It must dup them to 0,1 + */ set_close_on_exec((SOCKET)fdin[0], conn); /* stdin read */ set_close_on_exec((SOCKET)fdout[1], conn); /* stdout write */ set_close_on_exec((SOCKET)fderr[1], conn); /* stderr write */ @@ -7561,10 +10175,10 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) "Error: CGI program \"%s\": Can not open stdin: %s", prog, status); - send_http_error(conn, - 500, - "Error: CGI can not open fdin\nfopen: %s", - status); + mg_send_http_error(conn, + 500, + "Error: CGI can not open fdin\nfopen: %s", + status); goto done; } @@ -7574,10 +10188,10 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) "Error: CGI program \"%s\": Can not open stdout: %s", prog, status); - send_http_error(conn, - 500, - "Error: CGI can not open fdout\nfopen: %s", - status); + mg_send_http_error(conn, + 500, + "Error: CGI can not open fdout\nfopen: %s", + status); goto done; } @@ -7587,19 +10201,22 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) "Error: CGI program \"%s\": Can not open stderr: %s", prog, status); - send_http_error(conn, - 500, - "Error: CGI can not open fdout\nfopen: %s", - status); + mg_send_http_error(conn, + 500, + "Error: CGI can not open fdout\nfopen: %s", + status); goto done; } setbuf(in, NULL); setbuf(out, NULL); setbuf(err, NULL); - fout.fp = out; + fout.access.fp = out; + + if ((conn->request_info.content_length != 0) || (conn->is_chunked)) { + DEBUG_TRACE("CGI: send body data (%lli)\n", + (signed long long)conn->request_info.content_length); - if ((conn->request_info.content_length > 0) || conn->is_chunked) { /* This is a POST/PUT request, or another request with body data. */ if (!forward_body_data(conn, in, INVALID_SOCKET, NULL)) { /* Error sending the body data */ @@ -7620,12 +10237,12 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) * Do not send anything back to client, until we buffer in all * HTTP headers. */ data_len = 0; - buf = (char *)mg_malloc(buflen); + buf = (char *)mg_malloc_ctx(buflen, conn->ctx); if (buf == NULL) { - send_http_error(conn, - 500, - "Error: Not enough memory for CGI buffer (%u bytes)", - (unsigned int)buflen); + mg_send_http_error(conn, + 500, + "Error: Not enough memory for CGI buffer (%u bytes)", + (unsigned int)buflen); mg_cry(conn, "Error: CGI program \"%s\": Not enough memory for buffer (%u " "bytes)", @@ -7633,7 +10250,11 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) (unsigned int)buflen); goto done; } - headers_len = read_request(out, conn, buf, (int)buflen, &data_len); + + DEBUG_TRACE("CGI: %s", "wait for response"); + headers_len = read_message(out, conn, buf, (int)buflen, &data_len); + DEBUG_TRACE("CGI: response: %li", (signed long)headers_len); + if (headers_len <= 0) { /* Could not parse the CGI response. Check if some error message on @@ -7646,13 +10267,13 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) prog, i, buf); - send_http_error(conn, - 500, - "Error: CGI program \"%s\" sent error " - "message: [%.*s]", - prog, - i, - buf); + mg_send_http_error(conn, + 500, + "Error: CGI program \"%s\" sent error " + "message: [%.*s]", + prog, + i, + buf); } else { mg_cry(conn, "Error: CGI program sent malformed or too big " @@ -7661,39 +10282,46 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) data_len, buf); - send_http_error(conn, - 500, - "Error: CGI program sent malformed or too big " - "(>%u bytes) HTTP headers: [%.*s]", - (unsigned)buflen, - data_len, - buf); + mg_send_http_error(conn, + 500, + "Error: CGI program sent malformed or too big " + "(>%u bytes) HTTP headers: [%.*s]", + (unsigned)buflen, + data_len, + buf); } goto done; } + pbuf = buf; buf[headers_len - 1] = '\0'; - parse_http_headers(&pbuf, &ri); + ri.num_headers = parse_http_headers(&pbuf, ri.http_headers); /* Make up and send the status line */ status_text = "OK"; - if ((status = get_header(&ri, "Status")) != NULL) { + if ((status = get_header(ri.http_headers, ri.num_headers, "Status")) + != NULL) { conn->status_code = atoi(status); status_text = status; while (isdigit(*(const unsigned char *)status_text) || *status_text == ' ') { status_text++; } - } else if (get_header(&ri, "Location") != NULL) { + } else if (get_header(ri.http_headers, ri.num_headers, "Location") + != NULL) { conn->status_code = 302; } else { conn->status_code = 200; } - connection_state = get_header(&ri, "Connection"); + connection_state = + get_header(ri.http_headers, ri.num_headers, "Connection"); if (!header_has_option(connection_state, "keep-alive")) { conn->must_close = 1; } + + DEBUG_TRACE("CGI: response %u %s", conn->status_code, status_text); + (void)mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, status_text); /* Send headers */ @@ -7706,12 +10334,13 @@ handle_cgi_request(struct mg_connection *conn, const char *prog) mg_write(conn, "\r\n", 2); /* Send chunk of data that may have been read after the headers */ - conn->num_bytes_sent += - mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len)); + mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len)); /* Read the rest of CGI output and send to the client */ send_file_data(conn, &fout, 0, INT64_MAX); + DEBUG_TRACE("CGI: %s", "all data sent"); + done: mg_free(blk.var); mg_free(blk.buf); @@ -7771,7 +10400,8 @@ mkcol(struct mg_connection *conn, const char *path) return; } - /* TODO (mid): Check the send_http_error situations in this function */ + /* TODO (mid): Check the mg_send_http_error situations in this function + */ memset(&de.file, 0, sizeof(de.file)); if (!mg_stat(conn, path, &de.file)) { @@ -7783,15 +10413,17 @@ mkcol(struct mg_connection *conn, const char *path) } if (de.file.last_modified) { - /* TODO (high): This check does not seem to make any sense ! */ - send_http_error( + /* TODO (mid): This check does not seem to make any sense ! */ + /* TODO (mid): Add a webdav unit test first, before changing + * anything here. */ + mg_send_http_error( conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO)); return; } body_len = conn->data_len - conn->request_len; if (body_len > 0) { - send_http_error( + mg_send_http_error( conn, 415, "Error: mkcol(%s): %s", path, strerror(ERRNO)); return; } @@ -7807,22 +10439,24 @@ mkcol(struct mg_connection *conn, const char *path) conn->status_code, date); send_static_cache_header(conn); + send_additional_header(conn); mg_printf(conn, "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", suggest_connection_header(conn)); } else if (rc == -1) { if (errno == EEXIST) { - send_http_error( + mg_send_http_error( conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO)); } else if (errno == EACCES) { - send_http_error( + mg_send_http_error( conn, 403, "Error: mkcol(%s): %s", path, strerror(ERRNO)); } else if (errno == ENOENT) { - send_http_error( + mg_send_http_error( conn, 409, "Error: mkcol(%s): %s", path, strerror(ERRNO)); } else { - send_http_error(conn, 500, "fopen(%s): %s", path, strerror(ERRNO)); + mg_send_http_error( + conn, 500, "fopen(%s): %s", path, strerror(ERRNO)); } } } @@ -7831,7 +10465,7 @@ mkcol(struct mg_connection *conn, const char *path) static void put_file(struct mg_connection *conn, const char *path) { - struct file file = STRUCT_FILE_INITIALIZER; + struct mg_file file = STRUCT_FILE_INITIALIZER; const char *range; int64_t r1, r2; int rc; @@ -7842,11 +10476,11 @@ put_file(struct mg_connection *conn, const char *path) return; } - if (mg_stat(conn, path, &file)) { + if (mg_stat(conn, path, &file.stat)) { /* File already exists */ conn->status_code = 200; - if (file.is_directory) { + if (file.stat.is_directory) { /* This is an already existing directory, * so there is nothing to do for the server. */ rc = 0; @@ -7855,13 +10489,13 @@ put_file(struct mg_connection *conn, const char *path) /* File exists and is not a directory. */ /* Can it be replaced? */ - if (file.membuf != NULL) { + if (file.access.membuf != NULL) { /* This is an "in-memory" file, that can not be replaced */ - send_http_error( - conn, - 405, - "Error: Put not possible\nReplacing %s is not supported", - path); + mg_send_http_error(conn, + 405, + "Error: Put not possible\nReplacing %s " + "is not supported", + path); return; } @@ -7871,7 +10505,7 @@ put_file(struct mg_connection *conn, const char *path) conn->status_code = 200; rc = 1; } else { - send_http_error( + mg_send_http_error( conn, 403, "Error: Put not possible\nReplacing %s is not allowed", @@ -7893,6 +10527,7 @@ put_file(struct mg_connection *conn, const char *path) conn->status_code, mg_get_response_code_text(NULL, conn->status_code)); send_no_cache_header(conn); + send_additional_header(conn); mg_printf(conn, "Date: %s\r\n" "Content-Length: 0\r\n" @@ -7907,65 +10542,72 @@ put_file(struct mg_connection *conn, const char *path) if (rc == -1) { /* put_dir returns -1 if the path is too long */ - send_http_error(conn, - 414, - "Error: Path too long\nput_dir(%s): %s", - path, - strerror(ERRNO)); + mg_send_http_error(conn, + 414, + "Error: Path too long\nput_dir(%s): %s", + path, + strerror(ERRNO)); return; } if (rc == -2) { /* put_dir returns -2 if the directory can not be created */ - send_http_error(conn, - 500, - "Error: Can not create directory\nput_dir(%s): %s", - path, - strerror(ERRNO)); + mg_send_http_error(conn, + 500, + "Error: Can not create directory\nput_dir(%s): %s", + path, + strerror(ERRNO)); return; } /* A file should be created or overwritten. */ - if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) { - mg_fclose(&file); - send_http_error(conn, - 500, - "Error: Can not create file\nfopen(%s): %s", - path, - strerror(ERRNO)); + /* Currently CivetWeb does not nead read+write access. */ + if (!mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &file) + || file.access.fp == NULL) { + (void)mg_fclose(&file.access); + mg_send_http_error(conn, + 500, + "Error: Can not create file\nfopen(%s): %s", + path, + strerror(ERRNO)); return; } - fclose_on_exec(&file, conn); + fclose_on_exec(&file.access, conn); range = mg_get_header(conn, "Content-Range"); r1 = r2 = 0; - if (range != NULL && parse_range_header(range, &r1, &r2) > 0) { + if ((range != NULL) && parse_range_header(range, &r1, &r2) > 0) { conn->status_code = 206; /* Partial content */ - fseeko(file.fp, r1, SEEK_SET); + fseeko(file.access.fp, r1, SEEK_SET); } - if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) { + if (!forward_body_data(conn, file.access.fp, INVALID_SOCKET, NULL)) { /* forward_body_data failed. * The error code has already been sent to the client, * and conn->status_code is already set. */ - mg_fclose(&file); + (void)mg_fclose(&file.access); return; } + if (mg_fclose(&file.access) != 0) { + /* fclose failed. This might have different reasons, but a likely + * one is "no space on disk", http 507. */ + conn->status_code = 507; + } + gmt_time_string(date, sizeof(date), &curtime); mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, mg_get_response_code_text(NULL, conn->status_code)); send_no_cache_header(conn); + send_additional_header(conn); mg_printf(conn, "Date: %s\r\n" "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", date, suggest_connection_header(conn)); - - mg_fclose(&file); } @@ -7976,30 +10618,32 @@ delete_file(struct mg_connection *conn, const char *path) memset(&de.file, 0, sizeof(de.file)); if (!mg_stat(conn, path, &de.file)) { /* mg_stat returns 0 if the file does not exist */ - send_http_error(conn, - 404, - "Error: Cannot delete file\nFile %s not found", - path); + mg_send_http_error(conn, + 404, + "Error: Cannot delete file\nFile %s not found", + path); return; } - if (de.file.membuf != NULL) { - /* the file is cached in memory */ - send_http_error( - conn, - 405, - "Error: Delete not possible\nDeleting %s is not supported", - path); - return; - } +#if 0 /* Ignore if a file in memory is inside a folder */ + if (de.access.membuf != NULL) { + /* the file is cached in memory */ + mg_send_http_error( + conn, + 405, + "Error: Delete not possible\nDeleting %s is not supported", + path); + return; + } +#endif if (de.file.is_directory) { if (remove_directory(conn, path)) { /* Delete is successful: Return 204 without content. */ - send_http_error(conn, 204, "%s", ""); + mg_send_http_error(conn, 204, "%s", ""); } else { /* Delete is not successful: Return 500 (Server error). */ - send_http_error(conn, 500, "Error: Could not delete %s", path); + mg_send_http_error(conn, 500, "Error: Could not delete %s", path); } return; } @@ -8008,7 +10652,7 @@ delete_file(struct mg_connection *conn, const char *path) * Check if write permission is granted. */ if (access(path, W_OK) != 0) { /* File is read only */ - send_http_error( + mg_send_http_error( conn, 403, "Error: Delete not possible\nDeleting %s is not allowed", @@ -8019,21 +10663,21 @@ delete_file(struct mg_connection *conn, const char *path) /* Try to delete it. */ if (mg_remove(conn, path) == 0) { /* Delete was successful: Return 204 without content. */ - send_http_error(conn, 204, "%s", ""); + mg_send_http_error(conn, 204, "%s", ""); } else { /* Delete not successful (file locked). */ - send_http_error(conn, - 423, - "Error: Cannot delete file\nremove(%s): %s", - path, - strerror(ERRNO)); + mg_send_http_error(conn, + 423, + "Error: Cannot delete file\nremove(%s): %s", + path, + strerror(ERRNO)); } } #endif /* !NO_FILES */ static void -send_ssi_file(struct mg_connection *, const char *, struct file *, int); +send_ssi_file(struct mg_connection *, const char *, struct mg_file *, int); static void @@ -8043,7 +10687,7 @@ do_ssi_include(struct mg_connection *conn, int include_level) { char file_name[MG_BUF_LEN], path[512], *p; - struct file file = STRUCT_FILE_INITIALIZER; + struct mg_file file = STRUCT_FILE_INITIALIZER; size_t len; int truncated = 0; @@ -8072,8 +10716,8 @@ do_ssi_include(struct mg_connection *conn, (void) mg_snprintf(conn, &truncated, path, sizeof(path), "%s", file_name); - } else if (sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1 - || sscanf(tag, " \"%511[^\"]\"", file_name) == 1) { + } else if ((sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1) + || (sscanf(tag, " \"%511[^\"]\"", file_name) == 1)) { /* File name is relative to the currect document */ file_name[511] = 0; (void)mg_snprintf(conn, &truncated, path, sizeof(path), "%s", ssi); @@ -8101,14 +10745,14 @@ do_ssi_include(struct mg_connection *conn, return; } - if (!mg_fopen(conn, path, "rb", &file)) { + if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, &file)) { mg_cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", tag, path, strerror(ERRNO)); } else { - fclose_on_exec(&file, conn); + fclose_on_exec(&file.access, conn); if (match_prefix(conn->ctx->config[SSI_EXTENSIONS], strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) { @@ -8116,7 +10760,7 @@ do_ssi_include(struct mg_connection *conn, } else { send_file_data(conn, &file, 0, INT64_MAX); } - mg_fclose(&file); + (void)mg_fclose(&file.access); /* Ignore errors for readonly files */ } } @@ -8126,17 +10770,17 @@ static void do_ssi_exec(struct mg_connection *conn, char *tag) { char cmd[1024] = ""; - struct file file = STRUCT_FILE_INITIALIZER; + struct mg_file file = STRUCT_FILE_INITIALIZER; if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) { mg_cry(conn, "Bad SSI #exec: [%s]", tag); } else { cmd[1023] = 0; - if ((file.fp = popen(cmd, "r")) == NULL) { + if ((file.access.fp = popen(cmd, "r")) == NULL) { mg_cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO)); } else { send_file_data(conn, &file, 0, INT64_MAX); - pclose(file.fp); + pclose(file.access.fp); } } } @@ -8144,16 +10788,16 @@ do_ssi_exec(struct mg_connection *conn, char *tag) static int -mg_fgetc(struct file *filep, int offset) +mg_fgetc(struct mg_file *filep, int offset) { if (filep == NULL) { return EOF; } - if (filep->membuf != NULL && offset >= 0 - && ((unsigned int)(offset)) < filep->size) { - return ((const unsigned char *)filep->membuf)[offset]; - } else if (filep->fp != NULL) { - return fgetc(filep->fp); + if ((filep->access.membuf != NULL) && (offset >= 0) + && (((unsigned int)(offset)) < filep->stat.size)) { + return ((const unsigned char *)filep->access.membuf)[offset]; + } else if (filep->access.fp != NULL) { + return fgetc(filep->access.fp); } else { return EOF; } @@ -8163,67 +10807,94 @@ mg_fgetc(struct file *filep, int offset) static void send_ssi_file(struct mg_connection *conn, const char *path, - struct file *filep, + struct mg_file *filep, int include_level) { char buf[MG_BUF_LEN]; - int ch, offset, len, in_ssi_tag; + int ch, offset, len, in_tag, in_ssi_tag; if (include_level > 10) { mg_cry(conn, "SSI #include level is too deep (%s)", path); return; } - in_ssi_tag = len = offset = 0; - while ((ch = mg_fgetc(filep, offset)) != EOF) { - if (in_ssi_tag && ch == '>') { - in_ssi_tag = 0; - buf[len++] = (char)ch; - buf[len] = '\0'; - /* assert(len <= (int) sizeof(buf)); */ - if (len > (int)sizeof(buf)) { - break; - } - if (len < 6 || memcmp(buf, " example 'duk' linked to shared libduktape +# +# $ ls -l duk +# -rwxrwxr-x 1 duktape duktape 19407 Nov 30 15:48 duk +# +# $ ldd ./duk +# linux-vdso.so.1 => (0x00007ffd5ed3c000) +# libduktape.so.104 => /usr/local/lib/libduktape.so.104 (0x00007fb2f9753000) +# libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb2f944d000) +# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb2f9088000) +# /lib64/ld-linux-x86-64.so.2 (0x00007fb2f9991000) +# +# Based on: http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html + +# Soname version must be bumped whenever a binary compatibility change occurs +# (and should not be bumped when the library is compatible). A simple Duktape +# convention is to set soname version to (100*MAJOR + MINOR), e.g. 104 for +# Duktape 1.4.x, so that it gets automatically bumped for major and minor +# releases (potentially binary incompatible), but not for patch releases. +DUK_VERSION=10502 +SONAME_VERSION=105 +REAL_VERSION=$(SONAME_VERSION).$(DUK_VERSION) + +# Change to actual path for actual distribution packaging. +INSTALL_PREFIX=/usr/local + +# The 'noline' variant may be more appropriate for some distributions; it +# doesn't have #line directives in the combined source. +DUKTAPE_SRCDIR=./src +#DUKTAPE_SRCDIR=./src-noline + +.PHONY: all +all: libduktape.so.$(REAL_VERSION) libduktaped.so.$(REAL_VERSION) + +# If the default duk_config.h is not suitable for the distribution, modify it +# before compiling the shared library and copy the same, edited duk_config.h +# to $INSTALL_PREFIX/include on installation. + +libduktape.so.$(REAL_VERSION): + gcc -shared -fPIC -Wall -Wextra -Os -Wl,-soname,libduktape.so.$(SONAME_VERSION) \ + -o $@ $(DUKTAPE_SRCDIR)/duktape.c + +libduktaped.so.$(REAL_VERSION): + gcc -shared -fPIC -g -Wall -Wextra -Os -Wl,-soname,libduktaped.so.$(SONAME_VERSION) \ + -o $@ $(DUKTAPE_SRCDIR)/duktape.c + +# Symlinks depend on platform conventions. +.PHONY: install +install: libduktape.so.$(REAL_VERSION) libduktaped.so.$(REAL_VERSION) + cp $+ $(INSTALL_PREFIX)/lib/ + rm -f $(INSTALL_PREFIX)/lib/libduktape.so $(INSTALL_PREFIX)/lib/libduktape.so.$(SONAME_VERSION) + ln -s libduktape.so.$(REAL_VERSION) $(INSTALL_PREFIX)/lib/libduktape.so + ln -s libduktape.so.$(REAL_VERSION) $(INSTALL_PREFIX)/lib/libduktape.so.$(SONAME_VERSION) + rm -f $(INSTALL_PREFIX)/lib/libduktaped.so $(INSTALL_PREFIX)/lib/libduktaped.so.$(SONAME_VERSION) + ln -s libduktaped.so.$(REAL_VERSION) $(INSTALL_PREFIX)/lib/libduktaped.so + ln -s libduktaped.so.$(REAL_VERSION) $(INSTALL_PREFIX)/lib/libduktaped.so.$(SONAME_VERSION) + cp $(DUKTAPE_SRCDIR)/duktape.h $(DUKTAPE_SRCDIR)/duk_config.h $(INSTALL_PREFIX)/include/ + +# Note: assumes /usr/local/include/ and /usr/local/lib/ are in include/link +# path which may not be the case for all distributions. +#CCOPTS=-I/usr/local/include -L/usr/local/lib +CCOPTS= +duk: + gcc $(CCOPTS) -Wall -Wextra -Os -o $@ ./examples/cmdline/duk_cmdline.c -lduktape -lm diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/README.rst similarity index 79% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/README.rst index 78e72b956..65311a7c7 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/README.rst +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/README.rst @@ -61,6 +61,10 @@ This distributable contains: * ``src/``: main Duktape library in a "single source file" format (duktape.c, duktape.h, and duk_config.h). +* ``src-noline/``: contains a variant of ``src/duktape.c`` with no ``#line`` + directives which is preferable for some users. See discussion in + https://github.com/svaarala/duktape/pull/363. + * ``src-separate/``: main Duktape library in multiple files format. * ``config/``: genconfig utility for creating duk_config.h configuration @@ -81,7 +85,9 @@ This distributable contains: * ``debugger/``: a debugger with a web UI, see ``debugger/README.rst`` and https://github.com/svaarala/duktape/blob/master/doc/debugger.rst for - details on Duktape debugger support. + details on Duktape debugger support. Also contains a JSON debug proxy + (one written in Node.js and another in DukLuv) to make talking to the + debug target easier. * ``licenses/``: licensing information. @@ -89,14 +95,15 @@ You can find release notes at: * https://github.com/svaarala/duktape/blob/master/RELEASES.rst -This distributable contains Duktape version 1.3.0, created from git -commit 675165f35ea3a5bac34ff4d0a58b007cc2f442dc (v1.3.0). +This distributable contains Duktape version 1.5.2, created from git +commit cad34ae155acb0846545ca6bf2d29f9463b22bbb (v1.5.2). Duktape is copyrighted by its authors (see ``AUTHORS.rst``) and licensed -under the MIT license (see ``LICENSE.txt``). MurmurHash2 is used internally, -it is also under the MIT license. Duktape module loader is based on the -CommonJS module loading specification (without sharing any code), CommonJS -is under the MIT license. +under the MIT license (see ``LICENSE.txt``). String hashing algorithms are +based on the algorithm from Lua (MIT license), djb2 hash, and Murmurhash2 +(MIT license). Duktape module loader is based on the CommonJS module +loading specification (without sharing any code), CommonJS is under the +MIT license. Have fun! diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/config/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/config/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/config/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/duk_config.h-modular-dll b/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/duk_config.h-modular-dll new file mode 100644 index 000000000..5d5d0137c --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/duk_config.h-modular-dll @@ -0,0 +1,3415 @@ +/* + * duk_config.h configuration header generated by genconfig.py. + * + * Git commit: cad34ae155acb0846545ca6bf2d29f9463b22bbb + * Git describe: v1.5.2 + * Git branch: HEAD + * + * Supported platforms: + * - Mac OSX, iPhone, Darwin + * - OpenBSD + * - Generic BSD + * - Atari ST TOS + * - AmigaOS + * - Windows + * - Flashplayer (Crossbridge) + * - QNX + * - TI-Nspire + * - Emscripten + * - Linux + * - Solaris + * - Generic POSIX + * - Cygwin + * - Generic UNIX + * - Generic fallback + * + * Supported architectures: + * - x86 + * - x64 + * - x32 + * - ARM 32-bit + * - ARM 64-bit + * - MIPS 32-bit + * - MIPS 64-bit + * - PowerPC 32-bit + * - PowerPC 64-bit + * - SPARC 32-bit + * - SPARC 64-bit + * - SuperH + * - Motorola 68k + * - Emscripten + * - Generic + * + * Supported compilers: + * - Clang + * - GCC + * - MSVC + * - Emscripten + * - TinyC + * - VBCC + * - Bruce's C compiler + * - Generic + * + */ + +#if !defined(DUK_CONFIG_H_INCLUDED) +#define DUK_CONFIG_H_INCLUDED + +/* + * Intermediate helper defines + */ + +/* DLL build detection */ +#if defined(DUK_OPT_DLL_BUILD) +#define DUK_F_DLL_BUILD +#elif defined(DUK_OPT_NO_DLL_BUILD) +#undef DUK_F_DLL_BUILD +#else +/* configured for DLL build */ +#define DUK_F_DLL_BUILD +#endif + +/* Apple OSX, iOS */ +#if defined(__APPLE__) +#define DUK_F_APPLE +#endif + +/* OpenBSD */ +#if defined(__OpenBSD__) || defined(__OpenBSD) +#define DUK_F_OPENBSD +#endif + +/* NetBSD */ +#if defined(__NetBSD__) || defined(__NetBSD) +#define DUK_F_NETBSD +#endif + +/* FreeBSD */ +#if defined(__FreeBSD__) || defined(__FreeBSD) +#define DUK_F_FREEBSD +#endif + +/* BSD variant */ +#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ + defined(__bsdi__) || defined(__DragonFly__) +#define DUK_F_BSD +#endif + +/* Atari ST TOS. __TOS__ defined by PureC. No platform define in VBCC + * apparently, so to use with VBCC user must define __TOS__ manually. + */ +#if defined(__TOS__) +#define DUK_F_TOS +#endif + +/* Motorola 68K. Not defined by VBCC, so user must define one of these + * manually when using VBCC. + */ +#if defined(__m68k__) || defined(M68000) || defined(__MC68K__) +#define DUK_F_M68K +#endif + +/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must + * define 'AMIGA' manually when using VBCC. + */ +#if defined(AMIGA) || defined(__amigaos__) +#define DUK_F_AMIGAOS +#endif + +/* PowerPC */ +#if defined(__powerpc) || defined(__powerpc__) || defined(__PPC__) +#define DUK_F_PPC +#if defined(__PPC64__) || defined(__LP64__) || defined(_LP64) +#define DUK_F_PPC64 +#else +#define DUK_F_PPC32 +#endif +#endif + +/* Windows, both 32-bit and 64-bit */ +#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ + defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) +#define DUK_F_WINDOWS +#if defined(_WIN64) || defined(WIN64) +#define DUK_F_WIN64 +#else +#define DUK_F_WIN32 +#endif +#endif + +/* Flash player (e.g. Crossbridge) */ +#if defined(__FLASHPLAYER__) +#define DUK_F_FLASHPLAYER +#endif + +/* QNX */ +#if defined(__QNX__) +#define DUK_F_QNX +#endif + +/* TI-Nspire (using Ndless) */ +#if defined(_TINSPIRE) +#define DUK_F_TINSPIRE +#endif + +/* Emscripten (provided explicitly by user), improve if possible */ +#if defined(EMSCRIPTEN) +#define DUK_F_EMSCRIPTEN +#endif + +/* BCC (Bruce's C compiler): this is a "torture target" for compilation */ +#if defined(__BCC__) || defined(__BCC_VERSION__) +#define DUK_F_BCC +#endif + +/* Linux */ +#if defined(__linux) || defined(__linux__) || defined(linux) +#define DUK_F_LINUX +#endif + +/* illumos / Solaris */ +#if defined(__sun) && defined(__SVR4) +#define DUK_F_SUN +#endif + +/* POSIX */ +#if defined(__posix) +#define DUK_F_POSIX +#endif + +/* Cygwin */ +#if defined(__CYGWIN__) +#define DUK_F_CYGWIN +#endif + +/* Generic Unix (includes Cygwin) */ +#if defined(__unix) || defined(__unix__) || defined(unix) || \ + defined(DUK_F_LINUX) || defined(DUK_F_BSD) +#define DUK_F_UNIX +#endif + +/* stdint.h not available */ +#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) +#if (_MSC_VER < 1700) +/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ +#define DUK_F_NO_STDINT_H +#endif +#endif +#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC)) +#define DUK_F_NO_STDINT_H +#endif + +/* C++ */ +#undef DUK_F_CPP +#if defined(__cplusplus) +#define DUK_F_CPP +#endif + +/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), + * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. + * https://sites.google.com/site/x32abi/ + */ +#if defined(__amd64__) || defined(__amd64) || \ + defined(__x86_64__) || defined(__x86_64) || \ + defined(_M_X64) || defined(_M_AMD64) +#if defined(__ILP32__) || defined(_ILP32) +#define DUK_F_X32 +#else +#define DUK_F_X64 +#endif +#elif defined(i386) || defined(__i386) || defined(__i386__) || \ + defined(__i486__) || defined(__i586__) || defined(__i686__) || \ + defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \ + defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) +#if defined(__LP64__) || defined(_LP64) +/* This should not really happen, but would indicate x64. */ +#define DUK_F_X64 +#else +#define DUK_F_X86 +#endif +#endif + +/* ARM */ +#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) +#define DUK_F_ARM +#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) +#define DUK_F_ARM64 +#else +#define DUK_F_ARM32 +#endif +#endif + +/* MIPS. Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */ +#if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \ + defined(_R3000) || defined(_R4000) || defined(_R5900) || \ + defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \ + defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \ + defined(__mips) || defined(__MIPS__) +#define DUK_F_MIPS +#if defined(__LP64__) || defined(_LP64) || defined(__mips64) || \ + defined(__mips64__) || defined(__mips_n64) +#define DUK_F_MIPS64 +#else +#define DUK_F_MIPS32 +#endif +#endif + +/* SPARC */ +#if defined(sparc) || defined(__sparc) || defined(__sparc__) +#define DUK_F_SPARC +#if defined(__LP64__) || defined(_LP64) +#define DUK_F_SPARC64 +#else +#define DUK_F_SPARC32 +#endif +#endif + +/* SuperH */ +#if defined(__sh__) || \ + defined(__sh1__) || defined(__SH1__) || \ + defined(__sh2__) || defined(__SH2__) || \ + defined(__sh3__) || defined(__SH3__) || \ + defined(__sh4__) || defined(__SH4__) || \ + defined(__sh5__) || defined(__SH5__) +#define DUK_F_SUPERH +#endif + +/* Clang */ +#if defined(__clang__) +#define DUK_F_CLANG +#endif + +/* C99 or above */ +#undef DUK_F_C99 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define DUK_F_C99 +#endif + +/* C++11 or above */ +#undef DUK_F_CPP11 +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define DUK_F_CPP11 +#endif + +/* GCC. Clang also defines __GNUC__ so don't detect GCC if using Clang. */ +#if defined(__GNUC__) && !defined(__clang__) && !defined(DUK_F_CLANG) +#define DUK_F_GCC +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +/* Convenience, e.g. gcc 4.5.1 == 40501; http://stackoverflow.com/questions/6031819/emulating-gccs-builtin-unreachable */ +#define DUK_F_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__) +#else +#error cannot figure out gcc version +#endif +#endif + +/* MinGW. Also GCC flags (DUK_F_GCC) are enabled now. */ +#if defined(__MINGW32__) || defined(__MINGW64__) +#define DUK_F_MINGW +#endif + +/* MSVC */ +#if defined(_MSC_VER) +/* MSVC preprocessor defines: http://msdn.microsoft.com/en-us/library/b0084kay.aspx + * _MSC_FULL_VER includes the build number, but it has at least two formats, see e.g. + * BOOST_MSVC_FULL_VER in http://www.boost.org/doc/libs/1_52_0/boost/config/compiler/visualc.hpp + */ +#define DUK_F_MSVC +#if defined(_MSC_FULL_VER) +#if (_MSC_FULL_VER > 100000000) +#define DUK_F_MSVC_FULL_VER _MSC_FULL_VER +#else +#define DUK_F_MSCV_FULL_VER (_MSC_FULL_VER * 10) +#endif +#endif +#endif /* _MSC_VER */ + +/* TinyC */ +#if defined(__TINYC__) +/* http://bellard.org/tcc/tcc-doc.html#SEC9 */ +#define DUK_F_TINYC +#endif + +/* VBCC */ +#if defined(__VBCC__) +#define DUK_F_VBCC +#endif + +/* Atari Mint */ +#if defined(__MINT__) +#define DUK_F_MINT +#endif + +/* + * Platform autodetection + */ + +/* Workaround for older C++ compilers before including , + * see e.g.: https://sourceware.org/bugzilla/show_bug.cgi?id=15366 + */ +#if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS) +#define __STDC_LIMIT_MACROS +#endif +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) +#define __STDC_CONSTANT_MACROS +#endif + +#if defined(DUK_F_APPLE) +/* --- Mac OSX, iPhone, Darwin --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */ +#if TARGET_IPHONE_SIMULATOR +#define DUK_USE_OS_STRING "iphone-sim" +#elif TARGET_OS_IPHONE +#define DUK_USE_OS_STRING "iphone" +#elif TARGET_OS_MAC +#define DUK_USE_OS_STRING "osx" +#else +#define DUK_USE_OS_STRING "osx-unknown" +#endif + +/* Use _setjmp() on Apple by default, see GH-55. */ +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) +#elif defined(DUK_F_OPENBSD) +/* --- OpenBSD --- */ +/* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "openbsd" +#elif defined(DUK_F_BSD) +/* --- Generic BSD --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "bsd" +#elif defined(DUK_F_TOS) +/* --- Atari ST TOS --- */ +#define DUK_USE_DATE_NOW_TIME +#define DUK_USE_DATE_TZO_GMTIME +/* no parsing (not an error) */ +#define DUK_USE_DATE_FMT_STRFTIME +#include + +#define DUK_USE_OS_STRING "tos" + +/* TOS on M68K is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_M68K) +#define DUK_USE_BYTEORDER 3 +#endif +#elif defined(DUK_F_AMIGAOS) +/* --- AmigaOS --- */ +#if defined(DUK_F_M68K) +/* AmigaOS on M68k */ +#define DUK_USE_DATE_NOW_TIME +#define DUK_USE_DATE_TZO_GMTIME +/* no parsing (not an error) */ +#define DUK_USE_DATE_FMT_STRFTIME +#include +#elif defined(DUK_F_PPC) +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#ifndef UINTPTR_MAX +#define UINTPTR_MAX UINT_MAX +#endif +#else +#error AmigaOS but not M68K/PPC, not supported now +#endif + +#define DUK_USE_OS_STRING "amigaos" + +/* AmigaOS on M68K or PPC is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) +#define DUK_USE_BYTEORDER 3 +#endif +#elif defined(DUK_F_WINDOWS) +/* --- Windows --- */ +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* Windows 32-bit and 64-bit are currently the same. */ +/* MSVC does not have sys/param.h */ +#define DUK_USE_DATE_NOW_WINDOWS +#define DUK_USE_DATE_TZO_WINDOWS +/* Note: PRS and FMT are intentionally left undefined for now. This means + * there is no platform specific date parsing/formatting but there is still + * the ISO 8601 standard format. + */ +#if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ +#include +#endif + +#define DUK_USE_OS_STRING "windows" + +/* On Windows, assume we're little endian. Even Itanium which has a + * configurable endianness runs little endian in Windows. + */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#elif defined(DUK_F_FLASHPLAYER) +/* --- Flashplayer (Crossbridge) --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "flashplayer" + +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_FLASHPLAYER) +#define DUK_USE_BYTEORDER 1 +#endif +#elif defined(DUK_F_QNX) +/* --- QNX --- */ +#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE) +/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */ +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L +#endif + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "qnx" +#elif defined(DUK_F_TINSPIRE) +/* --- TI-Nspire --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "tinspire" +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include +#if defined(DUK_F_BCC) +/* no endian.h */ +#else +#include +#endif /* DUK_F_BCC */ +#include +#include +#include +#include + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#define DUK_USE_OS_STRING "emscripten" +#elif defined(DUK_F_LINUX) +/* --- Linux --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include +#if defined(DUK_F_BCC) +/* no endian.h or stdint.h */ +#else +#include +#include +#endif /* DUK_F_BCC */ +#include +#include +#include + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#define DUK_USE_OS_STRING "linux" +#elif defined(DUK_F_SUN) +/* --- Solaris --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "solaris" +#elif defined(DUK_F_POSIX) +/* --- Generic POSIX --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "posix" +#elif defined(DUK_F_CYGWIN) +/* --- Cygwin --- */ +/* don't use strptime() for now */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) + +#define DUK_USE_OS_STRING "windows" +#elif defined(DUK_F_UNIX) +/* --- Generic UNIX --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#define DUK_USE_OS_STRING "unknown" +#else +/* --- Generic fallback --- */ +/* The most portable current time provider is time(), but it only has a + * one second resolution. + */ +#define DUK_USE_DATE_NOW_TIME + +/* The most portable way to figure out local time offset is gmtime(), + * but it's not thread safe so use with caution. + */ +#define DUK_USE_DATE_TZO_GMTIME + +/* Avoid custom date parsing and formatting for portability. */ +#undef DUK_USE_DATE_PRS_STRPTIME +#undef DUK_USE_DATE_FMT_STRFTIME + +/* Rely on C89 headers only; time.h must be here. */ +#include + +#define DUK_USE_OS_STRING "unknown" +#endif /* autodetect platform */ + +/* Shared includes: C89 */ +#include +#include +#include +#include /* varargs */ +#include +#include /* e.g. ptrdiff_t */ +#include +#include + +/* date.h is omitted, and included per platform */ + +/* Shared includes: stdint.h is C99 */ +#if defined(DUK_F_NO_STDINT_H) +/* stdint.h not available */ +#else +/* Technically C99 (C++11) but found in many systems. On some systems + * __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS must be defined before + * including stdint.h (see above). + */ +#include +#endif + +#if defined(DUK_F_CPP) +#include /* std::exception */ +#endif + +/* + * Architecture autodetection + */ + +#if defined(DUK_F_X86) +/* --- x86 --- */ +#define DUK_USE_ARCH_STRING "x86" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X64) +/* --- x64 --- */ +#define DUK_USE_ARCH_STRING "x64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X32) +/* --- x32 --- */ +#define DUK_USE_ARCH_STRING "x32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM32) +/* --- ARM 32-bit --- */ +#define DUK_USE_ARCH_STRING "arm32" +/* Byte order varies, so rely on autodetect. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM64) +/* --- ARM 64-bit --- */ +#define DUK_USE_ARCH_STRING "arm64" +/* Byte order varies, so rely on autodetect. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS32) +/* --- MIPS 32-bit --- */ +#define DUK_USE_ARCH_STRING "mips32" +/* MIPS byte order varies so rely on autodetection. */ +/* Based on 'make checkalign' there are no alignment requirements on + * Linux MIPS except for doubles, which need align by 4. Alignment + * requirements vary based on target though. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS64) +/* --- MIPS 64-bit --- */ +#define DUK_USE_ARCH_STRING "mips64" +/* MIPS byte order varies so rely on autodetection. */ +/* Good default is a bit arbitrary because alignment requirements + * depend on target. See https://github.com/svaarala/duktape/issues/102. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC32) +/* --- PowerPC 32-bit --- */ +#define DUK_USE_ARCH_STRING "ppc32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC64) +/* --- PowerPC 64-bit --- */ +#define DUK_USE_ARCH_STRING "ppc64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC32) +/* --- SPARC 32-bit --- */ +#define DUK_USE_ARCH_STRING "sparc32" +/* SPARC byte order varies so rely on autodetection. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC64) +/* --- SPARC 64-bit --- */ +#define DUK_USE_ARCH_STRING "sparc64" +/* SPARC byte order varies so rely on autodetection. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SUPERH) +/* --- SuperH --- */ +#define DUK_USE_ARCH_STRING "sh" +/* Byte order varies, rely on autodetection. */ +/* Based on 'make checkalign' there are no alignment requirements on + * Linux SH4, but align by 4 is probably a good basic default. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_M68K) +/* --- Motorola 68k --- */ +#define DUK_USE_ARCH_STRING "m68k" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_USE_ARCH_STRING "emscripten" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#else +/* --- Generic --- */ +/* These are necessary wild guesses. */ +#define DUK_USE_ARCH_STRING "generic" +/* Rely on autodetection for byte order, alignment, and packed tval. */ +#endif /* autodetect architecture */ + +/* + * Compiler autodetection + */ + +#if defined(DUK_F_CLANG) +/* --- Clang --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* Clang: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#else +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "clang" +#else +#define DUK_USE_COMPILER_STRING "clang" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR +#elif defined(DUK_F_GCC) +/* --- GCC --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* GCC: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 20500L) +/* since gcc-2.5 */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* since gcc-4.5 */ +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif + +#define DUK_USE_BRANCH_HINTS +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* GCC: test not very accurate; enable only in relatively recent builds + * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html) + */ +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) +#endif + +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#elif defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40000) +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_MINGW) +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "mingw++" +#else +#define DUK_USE_COMPILER_STRING "mingw" +#endif +#else +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "g++" +#else +#define DUK_USE_COMPILER_STRING "gcc" +#endif +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__)) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40600) +#define DUK_USE_GCC_PRAGMAS +#else +#undef DUK_USE_GCC_PRAGMAS +#endif + +#define DUK_USE_PACK_GCC_ATTR +#elif defined(DUK_F_MSVC) +/* --- MSVC --- */ +/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */ +#define DUK_NORETURN(decl) __declspec(noreturn) decl + +/* XXX: DUK_UNREACHABLE for msvc? */ + +#undef DUK_USE_BRANCH_HINTS + +/* XXX: DUK_LIKELY, DUK_UNLIKELY for msvc? */ +/* XXX: DUK_NOINLINE, DUK_INLINE, DUK_ALWAYS_INLINE for msvc? */ + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "msvc++" +#else +#define DUK_USE_COMPILER_STRING "msvc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) +#define DUK_USE_VARIADIC_MACROS +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +/* VS2005+ should have variadic macros even when they're not C99. */ +#define DUK_USE_VARIADIC_MACROS +#endif + +#undef DUK_USE_UNION_INITIALIZERS +#if defined(_MSC_VER) && (_MSC_VER >= 1800) +/* VS2013+ supports union initializers but there's a bug involving union-inside-struct: + * https://connect.microsoft.com/VisualStudio/feedback/details/805981 + * The bug was fixed (at least) in VS2015 so check for VS2015 for now: + * https://blogs.msdn.microsoft.com/vcblog/2015/07/01/c-compiler-front-end-fixes-in-vs2015/ + * Manually tested using VS2013, CL reports 18.00.31101, so enable for VS2013 too. + */ +#define DUK_USE_UNION_INITIALIZERS +#endif + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS + +#define DUK_USE_PACK_MSVC_PRAGMA + +/* These have been tested from VS2008 onwards; may work in older VS versions + * too but not enabled by default. + */ +#if defined(_MSC_VER) && (_MSC_VER >= 1500) +#define DUK_NOINLINE __declspec(noinline) +#define DUK_INLINE __inline +#define DUK_ALWAYS_INLINE __forceinline +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) +#define DUK_SNPRINTF snprintf +#define DUK_VSNPRINTF vsnprintf +#else +/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does + * NOT NUL terminate on truncation, but Duktape code never assumes that. + * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 + */ +#define DUK_SNPRINTF _snprintf +#define DUK_VSNPRINTF _vsnprintf +#endif +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static + +#define DUK_USE_COMPILER_STRING "emscripten" + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR +#elif defined(DUK_F_TINYC) +/* --- TinyC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "tinyc++" +#else +#define DUK_USE_COMPILER_STRING "tinyc" +#endif + +/* http://bellard.org/tcc/tcc-doc.html#SEC7 */ +#define DUK_USE_VARIADIC_MACROS + +#define DUK_USE_UNION_INITIALIZERS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#elif defined(DUK_F_VBCC) +/* --- VBCC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "vbcc-c++" +#else +#define DUK_USE_COMPILER_STRING "vbcc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +/* VBCC supports C99 so check only for C99 for union initializer support. + * Designated union initializers would possibly work even without a C99 check. + */ +#undef DUK_USE_UNION_INITIALIZERS +#if defined(DUK_F_C99) +#define DUK_USE_UNION_INITIALIZERS +#endif + +#define DUK_USE_FLEX_ZEROSIZE +#define DUK_USE_PACK_DUMMY_MEMBER +#elif defined(DUK_F_BCC) +/* --- Bruce's C compiler --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "bcc++" +#else +#define DUK_USE_COMPILER_STRING "bcc" +#endif + +/* Most portable */ +#undef DUK_USE_VARIADIC_MACROS + +/* Most portable, wastes space */ +#undef DUK_USE_UNION_INITIALIZERS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER + +/* BCC, assume we're on x86. */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#else +/* --- Generic --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "generic-c++" +#else +#define DUK_USE_COMPILER_STRING "generic" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +/* C++ doesn't have standard designated union initializers ({ .foo = 1 }). */ +#undef DUK_USE_UNION_INITIALIZERS +#if defined(DUK_F_C99) +#define DUK_USE_UNION_INITIALIZERS +#endif + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#endif /* autodetect compiler */ + +/* uclibc */ +#if defined(__UCLIBC__) +#define DUK_F_UCLIBC +#endif + +/* + * Wrapper typedefs and constants for integer types, also sanity check types. + * + * C99 typedefs are quite good but not always available, and we want to avoid + * forcibly redefining the C99 typedefs. So, there are Duktape wrappers for + * all C99 typedefs and Duktape code should only use these typedefs. Type + * detection when C99 is not supported is best effort and may end up detecting + * some types incorrectly. + * + * Pointer sizes are a portability problem: pointers to different types may + * have a different size and function pointers are very difficult to manage + * portably. + * + * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types + * + * Note: there's an interesting corner case when trying to define minimum + * signed integer value constants which leads to the current workaround of + * defining e.g. -0x80000000 as (-0x7fffffffL - 1L). See doc/code-issues.txt + * for a longer discussion. + * + * Note: avoid typecasts and computations in macro integer constants as they + * can then no longer be used in macro relational expressions (such as + * #if DUK_SIZE_MAX < 0xffffffffUL). There is internal code which relies on + * being able to compare DUK_SIZE_MAX against a limit. + */ + +/* XXX: add feature options to force basic types from outside? */ + +#if !defined(INT_MAX) +#error INT_MAX not defined +#endif + +/* Check that architecture is two's complement, standard C allows e.g. + * INT_MIN to be -2**31+1 (instead of -2**31). + */ +#if defined(INT_MAX) && defined(INT_MIN) +#if INT_MAX != -(INT_MIN + 1) +#error platform does not seem complement of two +#endif +#else +#error cannot check complement of two +#endif + +/* Pointer size determination based on __WORDSIZE or architecture when + * that's not available. + */ +#if defined(DUK_F_X86) || defined(DUK_F_X32) || \ + defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ + defined(DUK_F_BCC) || \ + (defined(__WORDSIZE) && (__WORDSIZE == 32)) +#define DUK_F_32BIT_PTRS +#elif defined(DUK_F_X64) || \ + (defined(__WORDSIZE) && (__WORDSIZE == 64)) +#define DUK_F_64BIT_PTRS +#else +/* not sure, not needed with C99 anyway */ +#endif + +/* Intermediate define for 'have inttypes.h' */ +#undef DUK_F_HAVE_INTTYPES +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !(defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)) +/* vbcc + AmigaOS has C99 but no inttypes.h */ +#define DUK_F_HAVE_INTTYPES +#elif defined(__cplusplus) && (__cplusplus >= 201103L) +/* C++11 apparently ratified stdint.h */ +#define DUK_F_HAVE_INTTYPES +#endif + +/* Basic integer typedefs and limits, preferably from inttypes.h, otherwise + * through automatic detection. + */ +#if defined(DUK_F_HAVE_INTTYPES) +/* C99 or compatible */ + +#define DUK_F_HAVE_64BIT +#include + +typedef uint8_t duk_uint8_t; +typedef int8_t duk_int8_t; +typedef uint16_t duk_uint16_t; +typedef int16_t duk_int16_t; +typedef uint32_t duk_uint32_t; +typedef int32_t duk_int32_t; +typedef uint64_t duk_uint64_t; +typedef int64_t duk_int64_t; +typedef uint_least8_t duk_uint_least8_t; +typedef int_least8_t duk_int_least8_t; +typedef uint_least16_t duk_uint_least16_t; +typedef int_least16_t duk_int_least16_t; +typedef uint_least32_t duk_uint_least32_t; +typedef int_least32_t duk_int_least32_t; +typedef uint_least64_t duk_uint_least64_t; +typedef int_least64_t duk_int_least64_t; +typedef uint_fast8_t duk_uint_fast8_t; +typedef int_fast8_t duk_int_fast8_t; +typedef uint_fast16_t duk_uint_fast16_t; +typedef int_fast16_t duk_int_fast16_t; +typedef uint_fast32_t duk_uint_fast32_t; +typedef int_fast32_t duk_int_fast32_t; +typedef uint_fast64_t duk_uint_fast64_t; +typedef int_fast64_t duk_int_fast64_t; +typedef uintptr_t duk_uintptr_t; +typedef intptr_t duk_intptr_t; +typedef uintmax_t duk_uintmax_t; +typedef intmax_t duk_intmax_t; + +#define DUK_UINT8_MIN 0 +#define DUK_UINT8_MAX UINT8_MAX +#define DUK_INT8_MIN INT8_MIN +#define DUK_INT8_MAX INT8_MAX +#define DUK_UINT_LEAST8_MIN 0 +#define DUK_UINT_LEAST8_MAX UINT_LEAST8_MAX +#define DUK_INT_LEAST8_MIN INT_LEAST8_MIN +#define DUK_INT_LEAST8_MAX INT_LEAST8_MAX +#define DUK_UINT_FAST8_MIN 0 +#define DUK_UINT_FAST8_MAX UINT_FAST8_MAX +#define DUK_INT_FAST8_MIN INT_FAST8_MIN +#define DUK_INT_FAST8_MAX INT_FAST8_MAX +#define DUK_UINT16_MIN 0 +#define DUK_UINT16_MAX UINT16_MAX +#define DUK_INT16_MIN INT16_MIN +#define DUK_INT16_MAX INT16_MAX +#define DUK_UINT_LEAST16_MIN 0 +#define DUK_UINT_LEAST16_MAX UINT_LEAST16_MAX +#define DUK_INT_LEAST16_MIN INT_LEAST16_MIN +#define DUK_INT_LEAST16_MAX INT_LEAST16_MAX +#define DUK_UINT_FAST16_MIN 0 +#define DUK_UINT_FAST16_MAX UINT_FAST16_MAX +#define DUK_INT_FAST16_MIN INT_FAST16_MIN +#define DUK_INT_FAST16_MAX INT_FAST16_MAX +#define DUK_UINT32_MIN 0 +#define DUK_UINT32_MAX UINT32_MAX +#define DUK_INT32_MIN INT32_MIN +#define DUK_INT32_MAX INT32_MAX +#define DUK_UINT_LEAST32_MIN 0 +#define DUK_UINT_LEAST32_MAX UINT_LEAST32_MAX +#define DUK_INT_LEAST32_MIN INT_LEAST32_MIN +#define DUK_INT_LEAST32_MAX INT_LEAST32_MAX +#define DUK_UINT_FAST32_MIN 0 +#define DUK_UINT_FAST32_MAX UINT_FAST32_MAX +#define DUK_INT_FAST32_MIN INT_FAST32_MIN +#define DUK_INT_FAST32_MAX INT_FAST32_MAX +#define DUK_UINT64_MIN 0 +#define DUK_UINT64_MAX UINT64_MAX +#define DUK_INT64_MIN INT64_MIN +#define DUK_INT64_MAX INT64_MAX +#define DUK_UINT_LEAST64_MIN 0 +#define DUK_UINT_LEAST64_MAX UINT_LEAST64_MAX +#define DUK_INT_LEAST64_MIN INT_LEAST64_MIN +#define DUK_INT_LEAST64_MAX INT_LEAST64_MAX +#define DUK_UINT_FAST64_MIN 0 +#define DUK_UINT_FAST64_MAX UINT_FAST64_MAX +#define DUK_INT_FAST64_MIN INT_FAST64_MIN +#define DUK_INT_FAST64_MAX INT_FAST64_MAX + +#define DUK_UINTPTR_MIN 0 +#define DUK_UINTPTR_MAX UINTPTR_MAX +#define DUK_INTPTR_MIN INTPTR_MIN +#define DUK_INTPTR_MAX INTPTR_MAX + +#define DUK_UINTMAX_MIN 0 +#define DUK_UINTMAX_MAX UINTMAX_MAX +#define DUK_INTMAX_MIN INTMAX_MIN +#define DUK_INTMAX_MAX INTMAX_MAX + +#define DUK_SIZE_MIN 0 +#define DUK_SIZE_MAX SIZE_MAX +#undef DUK_SIZE_MAX_COMPUTED + +#else /* C99 types */ + +/* When C99 types are not available, we use heuristic detection to get + * the basic 8, 16, 32, and (possibly) 64 bit types. The fast/least + * types are then assumed to be exactly the same for now: these could + * be improved per platform but C99 types are very often now available. + * 64-bit types are not available on all platforms; this is OK at least + * on 32-bit platforms. + * + * This detection code is necessarily a bit hacky and can provide typedefs + * and defines that won't work correctly on some exotic platform. + */ + +#if (defined(CHAR_BIT) && (CHAR_BIT == 8)) || \ + (defined(UCHAR_MAX) && (UCHAR_MAX == 255)) +typedef unsigned char duk_uint8_t; +typedef signed char duk_int8_t; +#else +#error cannot detect 8-bit type +#endif + +#if defined(USHRT_MAX) && (USHRT_MAX == 65535UL) +typedef unsigned short duk_uint16_t; +typedef signed short duk_int16_t; +#elif defined(UINT_MAX) && (UINT_MAX == 65535UL) +/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ +typedef unsigned int duk_uint16_t; +typedef signed int duk_int16_t; +#else +#error cannot detect 16-bit type +#endif + +#if defined(UINT_MAX) && (UINT_MAX == 4294967295UL) +typedef unsigned int duk_uint32_t; +typedef signed int duk_int32_t; +#elif defined(ULONG_MAX) && (ULONG_MAX == 4294967295UL) +/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ +typedef unsigned long duk_uint32_t; +typedef signed long duk_int32_t; +#else +#error cannot detect 32-bit type +#endif + +/* 64-bit type detection is a bit tricky. + * + * ULLONG_MAX is a standard define. __LONG_LONG_MAX__ and __ULONG_LONG_MAX__ + * are used by at least GCC (even if system headers don't provide ULLONG_MAX). + * Some GCC variants may provide __LONG_LONG_MAX__ but not __ULONG_LONG_MAX__. + * + * ULL / LL constants are rejected / warned about by some compilers, even if + * the compiler has a 64-bit type and the compiler/system headers provide an + * unsupported constant (ULL/LL)! Try to avoid using ULL / LL constants. + * As a side effect we can only check that e.g. ULONG_MAX is larger than 32 + * bits but can't be sure it is exactly 64 bits. Self tests will catch such + * cases. + */ +#undef DUK_F_HAVE_64BIT +#if !defined(DUK_F_HAVE_64BIT) && defined(ULONG_MAX) +#if (ULONG_MAX > 4294967295UL) +#define DUK_F_HAVE_64BIT +typedef unsigned long duk_uint64_t; +typedef signed long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(ULLONG_MAX) +#if (ULLONG_MAX > 4294967295UL) +#define DUK_F_HAVE_64BIT +typedef unsigned long long duk_uint64_t; +typedef signed long long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(__ULONG_LONG_MAX__) +#if (__ULONG_LONG_MAX__ > 4294967295UL) +#define DUK_F_HAVE_64BIT +typedef unsigned long long duk_uint64_t; +typedef signed long long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(__LONG_LONG_MAX__) +#if (__LONG_LONG_MAX__ > 2147483647L) +#define DUK_F_HAVE_64BIT +typedef unsigned long long duk_uint64_t; +typedef signed long long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && \ + (defined(DUK_F_MINGW) || defined(DUK_F_MSVC)) +/* Both MinGW and MSVC have a 64-bit type. */ +#define DUK_F_HAVE_64BIT +typedef unsigned long duk_uint64_t; +typedef signed long duk_int64_t; +#endif +#if !defined(DUK_F_HAVE_64BIT) +/* cannot detect 64-bit type, not always needed so don't error */ +#endif + +typedef duk_uint8_t duk_uint_least8_t; +typedef duk_int8_t duk_int_least8_t; +typedef duk_uint16_t duk_uint_least16_t; +typedef duk_int16_t duk_int_least16_t; +typedef duk_uint32_t duk_uint_least32_t; +typedef duk_int32_t duk_int_least32_t; +typedef duk_uint8_t duk_uint_fast8_t; +typedef duk_int8_t duk_int_fast8_t; +typedef duk_uint16_t duk_uint_fast16_t; +typedef duk_int16_t duk_int_fast16_t; +typedef duk_uint32_t duk_uint_fast32_t; +typedef duk_int32_t duk_int_fast32_t; +#if defined(DUK_F_HAVE_64BIT) +typedef duk_uint64_t duk_uint_least64_t; +typedef duk_int64_t duk_int_least64_t; +typedef duk_uint64_t duk_uint_fast64_t; +typedef duk_int64_t duk_int_fast64_t; +#endif +#if defined(DUK_F_HAVE_64BIT) +typedef duk_uint64_t duk_uintmax_t; +typedef duk_int64_t duk_intmax_t; +#else +typedef duk_uint32_t duk_uintmax_t; +typedef duk_int32_t duk_intmax_t; +#endif + +/* Note: the funny looking computations for signed minimum 16-bit, 32-bit, and + * 64-bit values are intentional as the obvious forms (e.g. -0x80000000L) are + * -not- portable. See code-issues.txt for a detailed discussion. + */ +#define DUK_UINT8_MIN 0UL +#define DUK_UINT8_MAX 0xffUL +#define DUK_INT8_MIN (-0x80L) +#define DUK_INT8_MAX 0x7fL +#define DUK_UINT_LEAST8_MIN 0UL +#define DUK_UINT_LEAST8_MAX 0xffUL +#define DUK_INT_LEAST8_MIN (-0x80L) +#define DUK_INT_LEAST8_MAX 0x7fL +#define DUK_UINT_FAST8_MIN 0UL +#define DUK_UINT_FAST8_MAX 0xffUL +#define DUK_INT_FAST8_MIN (-0x80L) +#define DUK_INT_FAST8_MAX 0x7fL +#define DUK_UINT16_MIN 0UL +#define DUK_UINT16_MAX 0xffffUL +#define DUK_INT16_MIN (-0x7fffL - 1L) +#define DUK_INT16_MAX 0x7fffL +#define DUK_UINT_LEAST16_MIN 0UL +#define DUK_UINT_LEAST16_MAX 0xffffUL +#define DUK_INT_LEAST16_MIN (-0x7fffL - 1L) +#define DUK_INT_LEAST16_MAX 0x7fffL +#define DUK_UINT_FAST16_MIN 0UL +#define DUK_UINT_FAST16_MAX 0xffffUL +#define DUK_INT_FAST16_MIN (-0x7fffL - 1L) +#define DUK_INT_FAST16_MAX 0x7fffL +#define DUK_UINT32_MIN 0UL +#define DUK_UINT32_MAX 0xffffffffUL +#define DUK_INT32_MIN (-0x7fffffffL - 1L) +#define DUK_INT32_MAX 0x7fffffffL +#define DUK_UINT_LEAST32_MIN 0UL +#define DUK_UINT_LEAST32_MAX 0xffffffffUL +#define DUK_INT_LEAST32_MIN (-0x7fffffffL - 1L) +#define DUK_INT_LEAST32_MAX 0x7fffffffL +#define DUK_UINT_FAST32_MIN 0UL +#define DUK_UINT_FAST32_MAX 0xffffffffUL +#define DUK_INT_FAST32_MIN (-0x7fffffffL - 1L) +#define DUK_INT_FAST32_MAX 0x7fffffffL + +/* 64-bit constants. Since LL / ULL constants are not always available, + * use computed values. These values can't be used in preprocessor + * comparisons; flag them as such. + */ +#if defined(DUK_F_HAVE_64BIT) +#define DUK_UINT64_MIN ((duk_uint64_t) 0) +#define DUK_UINT64_MAX ((duk_uint64_t) -1) +#define DUK_INT64_MIN ((duk_int64_t) (~(DUK_UINT64_MAX >> 1))) +#define DUK_INT64_MAX ((duk_int64_t) (DUK_UINT64_MAX >> 1)) +#define DUK_UINT_LEAST64_MIN DUK_UINT64_MIN +#define DUK_UINT_LEAST64_MAX DUK_UINT64_MAX +#define DUK_INT_LEAST64_MIN DUK_INT64_MIN +#define DUK_INT_LEAST64_MAX DUK_INT64_MAX +#define DUK_UINT_FAST64_MIN DUK_UINT64_MIN +#define DUK_UINT_FAST64_MAX DUK_UINT64_MAX +#define DUK_INT_FAST64_MIN DUK_INT64_MIN +#define DUK_INT_FAST64_MAX DUK_INT64_MAX +#define DUK_UINT64_MIN_COMPUTED +#define DUK_UINT64_MAX_COMPUTED +#define DUK_INT64_MIN_COMPUTED +#define DUK_INT64_MAX_COMPUTED +#define DUK_UINT_LEAST64_MIN_COMPUTED +#define DUK_UINT_LEAST64_MAX_COMPUTED +#define DUK_INT_LEAST64_MIN_COMPUTED +#define DUK_INT_LEAST64_MAX_COMPUTED +#define DUK_UINT_FAST64_MIN_COMPUTED +#define DUK_UINT_FAST64_MAX_COMPUTED +#define DUK_INT_FAST64_MIN_COMPUTED +#define DUK_INT_FAST64_MAX_COMPUTED +#endif + +#if defined(DUK_F_HAVE_64BIT) +#define DUK_UINTMAX_MIN DUK_UINT64_MIN +#define DUK_UINTMAX_MAX DUK_UINT64_MAX +#define DUK_INTMAX_MIN DUK_INT64_MIN +#define DUK_INTMAX_MAX DUK_INT64_MAX +#define DUK_UINTMAX_MIN_COMPUTED +#define DUK_UINTMAX_MAX_COMPUTED +#define DUK_INTMAX_MIN_COMPUTED +#define DUK_INTMAX_MAX_COMPUTED +#else +#define DUK_UINTMAX_MIN 0UL +#define DUK_UINTMAX_MAX 0xffffffffUL +#define DUK_INTMAX_MIN (-0x7fffffffL - 1L) +#define DUK_INTMAX_MAX 0x7fffffffL +#endif + +/* This detection is not very reliable. */ +#if defined(DUK_F_32BIT_PTRS) +typedef duk_int32_t duk_intptr_t; +typedef duk_uint32_t duk_uintptr_t; +#define DUK_UINTPTR_MIN DUK_UINT32_MIN +#define DUK_UINTPTR_MAX DUK_UINT32_MAX +#define DUK_INTPTR_MIN DUK_INT32_MIN +#define DUK_INTPTR_MAX DUK_INT32_MAX +#elif defined(DUK_F_64BIT_PTRS) && defined(DUK_F_HAVE_64BIT) +typedef duk_int64_t duk_intptr_t; +typedef duk_uint64_t duk_uintptr_t; +#define DUK_UINTPTR_MIN DUK_UINT64_MIN +#define DUK_UINTPTR_MAX DUK_UINT64_MAX +#define DUK_INTPTR_MIN DUK_INT64_MIN +#define DUK_INTPTR_MAX DUK_INT64_MAX +#define DUK_UINTPTR_MIN_COMPUTED +#define DUK_UINTPTR_MAX_COMPUTED +#define DUK_INTPTR_MIN_COMPUTED +#define DUK_INTPTR_MAX_COMPUTED +#else +#error cannot determine intptr type +#endif + +/* SIZE_MAX may be missing so use an approximate value for it. */ +#undef DUK_SIZE_MAX_COMPUTED +#if !defined(SIZE_MAX) +#define DUK_SIZE_MAX_COMPUTED +#define SIZE_MAX ((size_t) (-1)) +#endif +#define DUK_SIZE_MIN 0 +#define DUK_SIZE_MAX SIZE_MAX + +#endif /* C99 types */ + +/* A few types are assumed to always exist. */ +typedef size_t duk_size_t; +typedef ptrdiff_t duk_ptrdiff_t; + +/* The best type for an "all around int" in Duktape internals is "at least + * 32 bit signed integer" which is most convenient. Same for unsigned type. + * Prefer 'int' when large enough, as it is almost always a convenient type. + */ +#if defined(UINT_MAX) && (UINT_MAX >= 0xffffffffUL) +typedef int duk_int_t; +typedef unsigned int duk_uint_t; +#define DUK_INT_MIN INT_MIN +#define DUK_INT_MAX INT_MAX +#define DUK_UINT_MIN 0 +#define DUK_UINT_MAX UINT_MAX +#else +typedef duk_int_fast32_t duk_int_t; +typedef duk_uint_fast32_t duk_uint_t; +#define DUK_INT_MIN DUK_INT_FAST32_MIN +#define DUK_INT_MAX DUK_INT_FAST32_MAX +#define DUK_UINT_MIN DUK_UINT_FAST32_MIN +#define DUK_UINT_MAX DUK_UINT_FAST32_MAX +#endif + +/* Same as 'duk_int_t' but guaranteed to be a 'fast' variant if this + * distinction matters for the CPU. These types are used mainly in the + * executor where it might really matter. + */ +typedef duk_int_fast32_t duk_int_fast_t; +typedef duk_uint_fast32_t duk_uint_fast_t; +#define DUK_INT_FAST_MIN DUK_INT_FAST32_MIN +#define DUK_INT_FAST_MAX DUK_INT_FAST32_MAX +#define DUK_UINT_FAST_MIN DUK_UINT_FAST32_MIN +#define DUK_UINT_FAST_MAX DUK_UINT_FAST32_MAX + +/* Small integers (16 bits or more) can fall back to the 'int' type, but + * have a typedef so they are marked "small" explicitly. + */ +typedef int duk_small_int_t; +typedef unsigned int duk_small_uint_t; +#define DUK_SMALL_INT_MIN INT_MIN +#define DUK_SMALL_INT_MAX INT_MAX +#define DUK_SMALL_UINT_MIN 0 +#define DUK_SMALL_UINT_MAX UINT_MAX + +/* Fast variants of small integers, again for really fast paths like the + * executor. + */ +typedef duk_int_fast16_t duk_small_int_fast_t; +typedef duk_uint_fast16_t duk_small_uint_fast_t; +#define DUK_SMALL_INT_FAST_MIN DUK_INT_FAST16_MIN +#define DUK_SMALL_INT_FAST_MAX DUK_INT_FAST16_MAX +#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN +#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX + +/* Boolean values are represented with the platform 'int'. */ +typedef duk_small_int_t duk_bool_t; +#define DUK_BOOL_MIN DUK_SMALL_INT_MIN +#define DUK_BOOL_MAX DUK_SMALL_INT_MAX + +/* Index values must have at least 32-bit signed range. */ +typedef duk_int_t duk_idx_t; +#define DUK_IDX_MIN DUK_INT_MIN +#define DUK_IDX_MAX DUK_INT_MAX + +/* Unsigned index variant. */ +typedef duk_uint_t duk_uidx_t; +#define DUK_UIDX_MIN DUK_UINT_MIN +#define DUK_UIDX_MAX DUK_UINT_MAX + +/* Array index values, could be exact 32 bits. + * Currently no need for signed duk_arridx_t. + */ +typedef duk_uint_t duk_uarridx_t; +#define DUK_UARRIDX_MIN DUK_UINT_MIN +#define DUK_UARRIDX_MAX DUK_UINT_MAX + +/* Duktape/C function return value, platform int is enough for now to + * represent 0, 1, or negative error code. Must be compatible with + * assigning truth values (e.g. duk_ret_t rc = (foo == bar);). + */ +typedef duk_small_int_t duk_ret_t; +#define DUK_RET_MIN DUK_SMALL_INT_MIN +#define DUK_RET_MAX DUK_SMALL_INT_MAX + +/* Error codes are represented with platform int. High bits are used + * for flags and such, so 32 bits are needed. + */ +typedef duk_int_t duk_errcode_t; +#define DUK_ERRCODE_MIN DUK_INT_MIN +#define DUK_ERRCODE_MAX DUK_INT_MAX + +/* Codepoint type. Must be 32 bits or more because it is used also for + * internal codepoints. The type is signed because negative codepoints + * are used as internal markers (e.g. to mark EOF or missing argument). + * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to + * ensure duk_uint32_t casts back and forth nicely. Almost everything + * else uses the signed one. + */ +typedef duk_int_t duk_codepoint_t; +typedef duk_uint_t duk_ucodepoint_t; +#define DUK_CODEPOINT_MIN DUK_INT_MIN +#define DUK_CODEPOINT_MAX DUK_INT_MAX +#define DUK_UCODEPOINT_MIN DUK_UINT_MIN +#define DUK_UCODEPOINT_MAX DUK_UINT_MAX + +/* IEEE float/double typedef. */ +typedef float duk_float_t; +typedef double duk_double_t; + +/* We're generally assuming that we're working on a platform with a 32-bit + * address space. If DUK_SIZE_MAX is a typecast value (which is necessary + * if SIZE_MAX is missing), the check must be avoided because the + * preprocessor can't do a comparison. + */ +#if !defined(DUK_SIZE_MAX) +#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX +#elif !defined(DUK_SIZE_MAX_COMPUTED) +#if DUK_SIZE_MAX < 0xffffffffUL +/* On some systems SIZE_MAX can be smaller than max unsigned 32-bit value + * which seems incorrect if size_t is (at least) an unsigned 32-bit type. + * However, it doesn't seem useful to error out compilation if this is the + * case. + */ +#endif +#endif + +/* Type for public API calls. */ +typedef struct duk_hthread duk_context; + +/* Check whether we should use 64-bit integers or not. + * + * Quite incomplete now. Use 64-bit types if detected (C99 or other detection) + * unless they are known to be unreliable. For instance, 64-bit types are + * available on VBCC but seem to misbehave. + */ +#if defined(DUK_F_HAVE_64BIT) && !defined(DUK_F_VBCC) +#define DUK_USE_64BIT_OPS +#else +#undef DUK_USE_64BIT_OPS +#endif + +/* + * Fill-ins for platform, architecture, and compiler + */ + +#if !defined(DUK_SETJMP) +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) setjmp((jb)) +#define DUK_LONGJMP(jb) longjmp((jb), 1) +#endif + +#if 0 +/* sigsetjmp() alternative */ +#define DUK_JMPBUF_TYPE sigjmp_buf +#define DUK_SETJMP(jb) sigsetjmp((jb)) +#define DUK_LONGJMP(jb) siglongjmp((jb), 1) +#endif + +typedef FILE duk_file; +#if !defined(DUK_STDIN) +#define DUK_STDIN stdin +#endif +#if !defined(DUK_STDOUT) +#define DUK_STDOUT stdout +#endif +#if !defined(DUK_STDERR) +#define DUK_STDERR stderr +#endif + +/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h + * (which is unfortunately named). May sometimes need replacement, e.g. + * some compilers don't handle zero length or NULL correctly in realloc(). + */ +#if !defined(DUK_ANSI_MALLOC) +#define DUK_ANSI_MALLOC malloc +#endif +#if !defined(DUK_ANSI_REALLOC) +#define DUK_ANSI_REALLOC realloc +#endif +#if !defined(DUK_ANSI_CALLOC) +#define DUK_ANSI_CALLOC calloc +#endif +#if !defined(DUK_ANSI_FREE) +#define DUK_ANSI_FREE free +#endif + +/* ANSI C (various versions) and some implementations require that the + * pointer arguments to memset(), memcpy(), and memmove() be valid values + * even when byte size is 0 (even a NULL pointer is considered invalid in + * this context). Zero-size operations as such are allowed, as long as their + * pointer arguments point to a valid memory area. The DUK_MEMSET(), + * DUK_MEMCPY(), and DUK_MEMMOVE() macros require this same behavior, i.e.: + * (1) pointers must be valid and non-NULL, (2) zero size must otherwise be + * allowed. If these are not fulfilled, a macro wrapper is needed. + * + * http://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0 + * http://lists.cs.uiuc.edu/pipermail/llvmdev/2007-October/011065.html + * + * Not sure what's the required behavior when a pointer points just past the + * end of a buffer, which often happens in practice (e.g. zero size memmoves). + * For example, if allocation size is 3, the following pointer would not + * technically point to a valid memory byte: + * + * <-- alloc --> + * | 0 | 1 | 2 | ..... + * ^-- p=3, points after last valid byte (2) + */ +#if !defined(DUK_MEMCPY) +#if defined(DUK_F_UCLIBC) +/* Old uclibcs have a broken memcpy so use memmove instead (this is overly wide + * now on purpose): http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html + */ +#define DUK_MEMCPY memmove +#else +#define DUK_MEMCPY memcpy +#endif +#endif +#if !defined(DUK_MEMMOVE) +#define DUK_MEMMOVE memmove +#endif +#if !defined(DUK_MEMCMP) +#define DUK_MEMCMP memcmp +#endif +#if !defined(DUK_MEMSET) +#define DUK_MEMSET memset +#endif +#if !defined(DUK_STRLEN) +#define DUK_STRLEN strlen +#endif +#if !defined(DUK_STRCMP) +#define DUK_STRCMP strcmp +#endif +#if !defined(DUK_STRNCMP) +#define DUK_STRNCMP strncmp +#endif +#if !defined(DUK_PRINTF) +#define DUK_PRINTF printf +#endif +#if !defined(DUK_FPRINTF) +#define DUK_FPRINTF fprintf +#endif +#if !defined(DUK_SPRINTF) +#define DUK_SPRINTF sprintf +#endif +#if !defined(DUK_SNPRINTF) +/* snprintf() is technically not part of C89 but usually available. */ +#define DUK_SNPRINTF snprintf +#endif +#if !defined(DUK_VSPRINTF) +#define DUK_VSPRINTF vsprintf +#endif +#if !defined(DUK_VSNPRINTF) +/* vsnprintf() is technically not part of C89 but usually available. */ +#define DUK_VSNPRINTF vsnprintf +#endif +#if !defined(DUK_SSCANF) +#define DUK_SSCANF sscanf +#endif +#if !defined(DUK_VSSCANF) +#define DUK_VSSCANF vsscanf +#endif +#if !defined(DUK_FOPEN) +#define DUK_FOPEN fopen +#endif +#if !defined(DUK_FCLOSE) +#define DUK_FCLOSE fclose +#endif +#if !defined(DUK_FREAD) +#define DUK_FREAD fread +#endif +#if !defined(DUK_FWRITE) +#define DUK_FWRITE fwrite +#endif +#if !defined(DUK_FSEEK) +#define DUK_FSEEK fseek +#endif +#if !defined(DUK_FTELL) +#define DUK_FTELL ftell +#endif +#if !defined(DUK_FFLUSH) +#define DUK_FFLUSH fflush +#endif +#if !defined(DUK_FPUTC) +#define DUK_FPUTC fputc +#endif +#if !defined(DUK_MEMZERO) +#define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n)) +#endif +#if !defined(DUK_ABORT) +#define DUK_ABORT abort +#endif +#if !defined(DUK_EXIT) +#define DUK_EXIT exit +#endif + +#if !defined(DUK_DOUBLE_2TO32) +#define DUK_DOUBLE_2TO32 4294967296.0 +#endif +#if !defined(DUK_DOUBLE_2TO31) +#define DUK_DOUBLE_2TO31 2147483648.0 +#endif + +#if !defined(DUK_DOUBLE_INFINITY) +#undef DUK_USE_COMPUTED_INFINITY +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION < 40600) +/* GCC older than 4.6: avoid overflow warnings related to using INFINITY */ +#define DUK_DOUBLE_INFINITY (__builtin_inf()) +#elif defined(INFINITY) +#define DUK_DOUBLE_INFINITY ((double) INFINITY) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#define DUK_DOUBLE_INFINITY (1.0 / 0.0) +#else +/* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. + * Use a computed infinity (initialized when a heap is created at the + * latest). + */ +#define DUK_USE_COMPUTED_INFINITY +#define DUK_DOUBLE_INFINITY duk_computed_infinity +#endif +#endif + +#if !defined(DUK_DOUBLE_NAN) +#undef DUK_USE_COMPUTED_NAN +#if defined(NAN) +#define DUK_DOUBLE_NAN NAN +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#define DUK_DOUBLE_NAN (0.0 / 0.0) +#else +/* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. + * In MSVC (VS2010 Express) (0.0 / 0.0) results in a compile error. + * Use a computed NaN (initialized when a heap is created at the + * latest). + */ +#define DUK_USE_COMPUTED_NAN +#define DUK_DOUBLE_NAN duk_computed_nan +#endif +#endif + +/* Many platforms are missing fpclassify() and friends, so use replacements + * if necessary. The replacement constants (FP_NAN etc) can be anything but + * match Linux constants now. + */ +#undef DUK_USE_REPL_FPCLASSIFY +#undef DUK_USE_REPL_SIGNBIT +#undef DUK_USE_REPL_ISFINITE +#undef DUK_USE_REPL_ISNAN +#undef DUK_USE_REPL_ISINF + +/* Complex condition broken into separate parts. */ +#undef DUK_F_USE_REPL_ALL +#if !(defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) && \ + defined(FP_SUBNORMAL) && defined(FP_NORMAL)) +/* Missing some obvious constants. */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC) +/* VBCC is missing the built-ins even in C99 mode (perhaps a header issue). */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_M68K) +/* AmigaOS + M68K seems to have math issues even when using GCC cross + * compilation. Use replacements for all AmigaOS versions on M68K + * regardless of compiler. + */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_FREEBSD) && defined(DUK_F_CLANG) +/* Placeholder fix for (detection is wider than necessary): + * http://llvm.org/bugs/show_bug.cgi?id=17788 + */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_UCLIBC) +/* At least some uclibc versions have broken floating point math. For + * example, fpclassify() can incorrectly classify certain NaN formats. + * To be safe, use replacements. + */ +#define DUK_F_USE_REPL_ALL +#endif + +#if defined(DUK_F_USE_REPL_ALL) +#define DUK_USE_REPL_FPCLASSIFY +#define DUK_USE_REPL_SIGNBIT +#define DUK_USE_REPL_ISFINITE +#define DUK_USE_REPL_ISNAN +#define DUK_USE_REPL_ISINF +#define DUK_FPCLASSIFY duk_repl_fpclassify +#define DUK_SIGNBIT duk_repl_signbit +#define DUK_ISFINITE duk_repl_isfinite +#define DUK_ISNAN duk_repl_isnan +#define DUK_ISINF duk_repl_isinf +#define DUK_FP_NAN 0 +#define DUK_FP_INFINITE 1 +#define DUK_FP_ZERO 2 +#define DUK_FP_SUBNORMAL 3 +#define DUK_FP_NORMAL 4 +#else +#define DUK_FPCLASSIFY fpclassify +#define DUK_SIGNBIT signbit +#define DUK_ISFINITE isfinite +#define DUK_ISNAN isnan +#define DUK_ISINF isinf +#define DUK_FP_NAN FP_NAN +#define DUK_FP_INFINITE FP_INFINITE +#define DUK_FP_ZERO FP_ZERO +#define DUK_FP_SUBNORMAL FP_SUBNORMAL +#define DUK_FP_NORMAL FP_NORMAL +#endif + +#if defined(DUK_F_USE_REPL_ALL) +#undef DUK_F_USE_REPL_ALL +#endif + +/* Some math functions are C99 only. This is also an issue with some + * embedded environments using uclibc where uclibc has been configured + * not to provide some functions. For now, use replacements whenever + * using uclibc. + */ +#undef DUK_USE_MATH_FMIN +#undef DUK_USE_MATH_FMAX +#undef DUK_USE_MATH_ROUND +#if defined(DUK_F_UCLIBC) +/* uclibc may be missing these */ +#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC) +/* vbcc + AmigaOS may be missing these */ +#elif defined(DUK_F_MINT) +/* mint clib is missing these */ +#elif !defined(DUK_F_C99) && !defined(DUK_F_CPP11) +/* build is not C99 or C++11, play it safe */ +#else +/* C99 or C++11, no known issues */ +#define DUK_USE_MATH_FMIN +#define DUK_USE_MATH_FMAX +#define DUK_USE_MATH_ROUND +#endif + +/* These functions don't currently need replacement but are wrapped for + * completeness. Because these are used as function pointers, they need + * to be defined as concrete C functions (not macros). + */ +#if !defined(DUK_FABS) +#define DUK_FABS fabs +#endif +#if !defined(DUK_FMIN) +#define DUK_FMIN fmin +#endif +#if !defined(DUK_FMAX) +#define DUK_FMAX fmax +#endif +#if !defined(DUK_FLOOR) +#define DUK_FLOOR floor +#endif +#if !defined(DUK_CEIL) +#define DUK_CEIL ceil +#endif +#if !defined(DUK_FMOD) +#define DUK_FMOD fmod +#endif +#if !defined(DUK_POW) +#define DUK_POW pow +#endif +#if !defined(DUK_ACOS) +#define DUK_ACOS acos +#endif +#if !defined(DUK_ASIN) +#define DUK_ASIN asin +#endif +#if !defined(DUK_ATAN) +#define DUK_ATAN atan +#endif +#if !defined(DUK_ATAN2) +#define DUK_ATAN2 atan2 +#endif +#if !defined(DUK_SIN) +#define DUK_SIN sin +#endif +#if !defined(DUK_COS) +#define DUK_COS cos +#endif +#if !defined(DUK_TAN) +#define DUK_TAN tan +#endif +#if !defined(DUK_EXP) +#define DUK_EXP exp +#endif +#if !defined(DUK_LOG) +#define DUK_LOG log +#endif +#if !defined(DUK_SQRT) +#define DUK_SQRT sqrt +#endif + +/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, + * see test-bug-netbsd-math-pow.js. Use NetBSD specific workaround. + * (This might be a wider problem; if so, generalize the define name.) + */ +#undef DUK_USE_POW_NETBSD_WORKAROUND +#if defined(DUK_F_NETBSD) +#define DUK_USE_POW_NETBSD_WORKAROUND +#endif + +/* Rely as little as possible on compiler behavior for NaN comparison, + * signed zero handling, etc. Currently never activated but may be needed + * for broken compilers. + */ +#undef DUK_USE_PARANOID_MATH + +/* There was a curious bug where test-bi-date-canceling.js would fail e.g. + * on 64-bit Ubuntu, gcc-4.8.1, -m32, and no -std=c99. Some date computations + * using doubles would be optimized which then broke some corner case tests. + * The problem goes away by adding 'volatile' to the datetime computations. + * Not sure what the actual triggering conditions are, but using this on + * non-C99 systems solves the known issues and has relatively little cost + * on other platforms. + */ +#undef DUK_USE_PARANOID_DATE_COMPUTATION +#if !defined(DUK_F_C99) +#define DUK_USE_PARANOID_DATE_COMPUTATION +#endif + +/* + * Byte order and double memory layout detection + * + * Endianness detection is a major portability hassle because the macros + * and headers are not standardized. There's even variance across UNIX + * platforms. Even with "standard" headers, details like underscore count + * varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used + * (Crossbridge has a single underscore, for instance). + * + * The checks below are structured with this in mind: several approaches are + * used, and at the end we check if any of them worked. This allows generic + * approaches to be tried first, and platform/compiler specific hacks tried + * last. As a last resort, the user can force a specific endianness, as it's + * not likely that automatic detection will work on the most exotic platforms. + * + * Duktape supports little and big endian machines. There's also support + * for a hybrid used by some ARM machines where integers are little endian + * but IEEE double values use a mixed order (12345678 -> 43218765). This + * byte order for doubles is referred to as "mixed endian". + */ + +/* For custom platforms allow user to define byteorder explicitly. + * Since endianness headers are not standardized, this is a useful + * workaround for custom platforms for which endianness detection + * is not directly supported. Perhaps custom hardware is used and + * user cannot submit upstream patches. + */ +#if defined(DUK_OPT_FORCE_BYTEORDER) +#undef DUK_USE_BYTEORDER +#if (DUK_OPT_FORCE_BYTEORDER == 1) +#define DUK_USE_BYTEORDER 1 +#elif (DUK_OPT_FORCE_BYTEORDER == 2) +#define DUK_USE_BYTEORDER 2 +#elif (DUK_OPT_FORCE_BYTEORDER == 3) +#define DUK_USE_BYTEORDER 3 +#else +#error invalid DUK_OPT_FORCE_BYTEORDER value +#endif +#endif /* DUK_OPT_FORCE_BYTEORDER */ + +/* GCC and Clang provide endianness defines as built-in predefines, with + * leading and trailing double underscores (e.g. __BYTE_ORDER__). See + * output of "make gccpredefs" and "make clangpredefs". Clang doesn't + * seem to provide __FLOAT_WORD_ORDER__; assume not mixed endian for clang. + * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html + */ +#if !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) +#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 +#else +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit + * integer ordering and is not relevant. + */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) */ + +/* More or less standard endianness predefines provided by header files. + * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER + * will be big endian, see: http://lists.mysql.com/internals/443. + * On some platforms some defines may be present with an empty value which + * causes comparisons to fail: https://github.com/svaarala/duktape/issues/453. + */ +#if !defined(DUK_USE_BYTEORDER) +#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \ + defined(__LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 +#else +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order. */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) */ + +/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__: + * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - > 24) | \ + ((((duk_uint32_t) (x)) >> 8) & 0xff00UL) | \ + ((((duk_uint32_t) (x)) << 8) & 0xff0000UL) | \ + (((duk_uint32_t) (x)) << 24)) +#endif +#if !defined(DUK_BSWAP16) +#define DUK_BSWAP16(x) \ + ((duk_uint16_t) (x) >> 8) | \ + ((duk_uint16_t) (x) << 8) +#endif + +/* DUK_USE_VARIADIC_MACROS: required from compilers, so no fill-in. */ +/* DUK_USE_UNION_INITIALIZERS: required from compilers, so no fill-in. */ + +#if !(defined(DUK_USE_FLEX_C99) || defined(DUK_USE_FLEX_ZEROSIZE) || defined(DUK_USE_FLEX_ONESIZE)) +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE /* Not standard but common enough */ +#endif +#endif + +#if !(defined(DUK_USE_PACK_GCC_ATTR) || defined(DUK_USE_PACK_CLANG_ATTR) || \ + defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_DUMMY_MEMBER)) +#define DUK_USE_PACK_DUMMY_MEMBER +#endif + +#if 0 /* not defined by default */ +#undef DUK_USE_GCC_PRAGMAS +#endif + +/* Workaround for GH-323: avoid inlining control when compiling from + * multiple sources, as it causes compiler portability trouble. + */ +#if !defined(DUK_SINGLE_FILE) +#undef DUK_NOINLINE +#undef DUK_INLINE +#undef DUK_ALWAYS_INLINE +#define DUK_NOINLINE /*nop*/ +#define DUK_INLINE /*nop*/ +#define DUK_ALWAYS_INLINE /*nop*/ +#endif + +/* + * Check whether or not a packed duk_tval representation is possible. + * What's basically required is that pointers are 32-bit values + * (sizeof(void *) == 4). Best effort check, not always accurate. + * If guess goes wrong, crashes may result; self tests also verify + * the guess. + */ + +/* Explicit marker needed; may be 'defined', 'undefined, 'or 'not provided'. */ +#if !defined(DUK_F_PACKED_TVAL_PROVIDED) +#undef DUK_F_PACKED_TVAL_POSSIBLE + +/* Strict C99 case: DUK_UINTPTR_MAX (= UINTPTR_MAX) should be very reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif + +/* Non-C99 case, still relying on DUK_UINTPTR_MAX, as long as it is not a computed value */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif + +/* DUK_SIZE_MAX (= SIZE_MAX) is often reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED) +#if (DUK_SIZE_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif + +#undef DUK_USE_PACKED_TVAL +#if defined(DUK_F_PACKED_TVAL_POSSIBLE) +#define DUK_USE_PACKED_TVAL +#endif + +#undef DUK_F_PACKED_TVAL_POSSIBLE +#endif /* DUK_F_PACKED_TVAL_PROVIDED */ + +/* Feature option forcing. */ +#if defined(DUK_OPT_NO_PACKED_TVAL) +#undef DUK_USE_PACKED_TVAL +#elif defined(DUK_OPT_PACKED_TVAL) +#undef DUK_USE_PACKED_TVAL +#define DUK_USE_PACKED_TVAL +#endif +/* Object property allocation layout has implications for memory and code + * footprint and generated code size/speed. The best layout also depends + * on whether the platform has alignment requirements or benefits from + * having mostly aligned accesses. + */ +#undef DUK_USE_HOBJECT_LAYOUT_1 +#undef DUK_USE_HOBJECT_LAYOUT_2 +#undef DUK_USE_HOBJECT_LAYOUT_3 +#if (DUK_USE_ALIGN_BY == 1) +/* On platforms without any alignment issues, layout 1 is preferable + * because it compiles to slightly less code and provides direct access + * to property keys. + */ +#define DUK_USE_HOBJECT_LAYOUT_1 +#else +/* On other platforms use layout 2, which requires some padding but + * is a bit more natural than layout 3 in ordering the entries. Layout + * 3 is currently not used. + */ +#define DUK_USE_HOBJECT_LAYOUT_2 +#endif + +/* GCC/clang inaccurate math would break compliance and probably duk_tval, + * so refuse to compile. Relax this if -ffast-math is tested to work. + */ +#if defined(__FAST_MATH__) +#error __FAST_MATH__ defined, refusing to compile +#endif + +/* + * Autogenerated defaults + */ + +#undef DUK_USE_ASSERTIONS +#define DUK_USE_AUGMENT_ERROR_CREATE +#define DUK_USE_AUGMENT_ERROR_THROW +#define DUK_USE_AVOID_PLATFORM_FUNCPTRS +#define DUK_USE_BASE64_FASTPATH +#define DUK_USE_BROWSER_LIKE +#define DUK_USE_BUFFEROBJECT_SUPPORT +#undef DUK_USE_BUFLEN16 +#define DUK_USE_BUILTIN_INITJS +#define DUK_USE_BYTECODE_DUMP_SUPPORT +#define DUK_USE_COMMONJS_MODULES +#define DUK_USE_COMPILER_RECLIMIT 2500 +#undef DUK_USE_CPP_EXCEPTIONS +#undef DUK_USE_DATAPTR16 +#undef DUK_USE_DATAPTR_DEC16 +#undef DUK_USE_DATAPTR_ENC16 +#undef DUK_USE_DATE_FORMAT_STRING +#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET +#undef DUK_USE_DATE_GET_NOW +#undef DUK_USE_DATE_PARSE_STRING +#undef DUK_USE_DATE_PRS_GETDATE +#undef DUK_USE_DDDPRINT +#undef DUK_USE_DDPRINT +#undef DUK_USE_DEBUG +#undef DUK_USE_DEBUGGER_DUMPHEAP +#undef DUK_USE_DEBUGGER_FWD_LOGGING +#undef DUK_USE_DEBUGGER_FWD_PRINTALERT +#undef DUK_USE_DEBUGGER_INSPECT +#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT +#undef DUK_USE_DEBUGGER_SUPPORT +#define DUK_USE_DEBUGGER_THROW_NOTIFY +#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE +#define DUK_USE_DEBUG_BUFSIZE 65536L +#define DUK_USE_DOUBLE_LINKED_HEAP +#undef DUK_USE_DPRINT +#undef DUK_USE_DPRINT_COLORS +#undef DUK_USE_DPRINT_RDTSC +#define DUK_USE_ERRCREATE +#define DUK_USE_ERRTHROW +#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY +#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF +#define DUK_USE_ES6_PROXY +#define DUK_USE_ES6_REGEXP_BRACES +#define DUK_USE_ESBC_LIMITS +#define DUK_USE_ESBC_MAX_BYTES 2147418112L +#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L +#undef DUK_USE_EXEC_FUN_LOCAL +#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK +#undef DUK_USE_EXEC_TIMEOUT_CHECK +#undef DUK_USE_EXPLICIT_NULL_INIT +#undef DUK_USE_EXTSTR_FREE +#undef DUK_USE_EXTSTR_INTERN_CHECK +#undef DUK_USE_FASTINT +#define DUK_USE_FAST_REFCOUNT_DEFAULT +#define DUK_USE_FILE_IO +#undef DUK_USE_FUNCPTR16 +#undef DUK_USE_FUNCPTR_DEC16 +#undef DUK_USE_FUNCPTR_ENC16 +#undef DUK_USE_GC_TORTURE +#undef DUK_USE_HEAPPTR16 +#undef DUK_USE_HEAPPTR_DEC16 +#undef DUK_USE_HEAPPTR_ENC16 +#define DUK_USE_HEX_FASTPATH +#define DUK_USE_HOBJECT_HASH_PART +#define DUK_USE_HSTRING_CLEN +#undef DUK_USE_HSTRING_EXTDATA +#define DUK_USE_IDCHAR_FASTPATH +#undef DUK_USE_INTERRUPT_COUNTER +#undef DUK_USE_INTERRUPT_DEBUG_FIXUP +#define DUK_USE_JC +#define DUK_USE_JSON_DECNUMBER_FASTPATH +#define DUK_USE_JSON_DECSTRING_FASTPATH +#define DUK_USE_JSON_DEC_RECLIMIT 1000 +#define DUK_USE_JSON_EATWHITE_FASTPATH +#define DUK_USE_JSON_ENC_RECLIMIT 1000 +#define DUK_USE_JSON_QUOTESTRING_FASTPATH +#undef DUK_USE_JSON_STRINGIFY_FASTPATH +#define DUK_USE_JX +#define DUK_USE_LEXER_SLIDING_WINDOW +#undef DUK_USE_LIGHTFUNC_BUILTINS +#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE +#define DUK_USE_MARK_AND_SWEEP +#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 +#define DUK_USE_MATH_BUILTIN +#define DUK_USE_MS_STRINGTABLE_RESIZE +#define DUK_USE_NATIVE_CALL_RECLIMIT 1000 +#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER +#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER +#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT +#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY +#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY +#define DUK_USE_NONSTD_FUNC_STMT +#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT +#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029 +#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE +#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT +#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT +#undef DUK_USE_OBJSIZES16 +#define DUK_USE_OCTAL_SUPPORT +#define DUK_USE_PANIC_ABORT +#undef DUK_USE_PANIC_EXIT +#undef DUK_USE_PANIC_HANDLER +#undef DUK_USE_PANIC_SEGFAULT +#undef DUK_USE_PARANOID_ERRORS +#define DUK_USE_PC2LINE +#undef DUK_USE_PREFER_SIZE +#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS +#undef DUK_USE_REFCOUNT16 +#define DUK_USE_REFERENCE_COUNTING +#undef DUK_USE_REFZERO_FINALIZER_TORTURE +#undef DUK_USE_REGEXP_CANON_WORKAROUND +#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 +#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 +#define DUK_USE_REGEXP_SUPPORT +#undef DUK_USE_ROM_GLOBAL_CLONE +#undef DUK_USE_ROM_GLOBAL_INHERIT +#undef DUK_USE_ROM_OBJECTS +#define DUK_USE_ROM_PTRCOMP_FIRST 63488L +#undef DUK_USE_ROM_STRINGS +#define DUK_USE_SECTION_B +#undef DUK_USE_SELF_TESTS +#undef DUK_USE_SHUFFLE_TORTURE +#define DUK_USE_SOURCE_NONBMP +#undef DUK_USE_STRHASH16 +#undef DUK_USE_STRHASH_DENSE +#define DUK_USE_STRHASH_SKIP_SHIFT 5 +#define DUK_USE_STRICT_DECL +#undef DUK_USE_STRICT_UTF8_SOURCE +#undef DUK_USE_STRLEN16 +#undef DUK_USE_STRTAB_CHAIN +#undef DUK_USE_STRTAB_CHAIN_SIZE +#define DUK_USE_STRTAB_PROBE +#define DUK_USE_TAILCALL +#define DUK_USE_TARGET_INFO "unknown" +#define DUK_USE_TRACEBACKS +#define DUK_USE_TRACEBACK_DEPTH 10 +#define DUK_USE_USER_DECLARE() /* no user declarations */ +#undef DUK_USE_USER_INITJS +#undef DUK_USE_VALSTACK_UNSAFE +#define DUK_USE_VERBOSE_ERRORS +#define DUK_USE_VERBOSE_EXECUTOR_ERRORS +#define DUK_USE_VOLUNTARY_GC +#define DUK_USE_ZERO_BUFFER_DATA + +/* + * Alternative customization header + * + * If you want to modify the final DUK_USE_xxx flags directly (without + * using the available DUK_OPT_xxx flags), define DUK_OPT_HAVE_CUSTOM_H + * and tweak the final flags there. + */ + +#if defined(DUK_OPT_HAVE_CUSTOM_H) +#include "duk_custom.h" +#endif + +/* + * You may add overriding #define/#undef directives below for + * customization. You of course cannot un-#include or un-typedef + * anything; these require direct changes above. + */ + +/* __OVERRIDE_DEFINES__ */ + +/* + * Date provider selection + * + * User may define DUK_USE_DATE_GET_NOW() etc directly, in which case we'll + * rely on an external provider. If this is not done, revert to previous + * behavior and use Unix/Windows built-in provider. + */ + +#if defined(DUK_COMPILING_DUKTAPE) + +#if defined(DUK_USE_DATE_GET_NOW) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday((ctx)) +#elif defined(DUK_USE_DATE_NOW_TIME) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time((ctx)) +#elif defined(DUK_USE_DATE_NOW_WINDOWS) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows((ctx)) +#else +#error no provider for DUK_USE_DATE_GET_NOW() +#endif + +#if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) +#elif defined(DUK_USE_DATE_TZO_WINDOWS) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) +#else +#error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() +#endif + +#if defined(DUK_USE_DATE_PARSE_STRING) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_PRS_STRPTIME) +#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_strptime((ctx), (str)) +#elif defined(DUK_USE_DATE_PRS_GETDATE) +#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_getdate((ctx), (str)) +#else +/* No provider for DUK_USE_DATE_PARSE_STRING(), fall back to ISO 8601 only. */ +#endif + +#if defined(DUK_USE_DATE_FORMAT_STRING) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_FMT_STRFTIME) +#define DUK_USE_DATE_FORMAT_STRING(ctx,parts,tzoffset,flags) \ + duk_bi_date_format_parts_strftime((ctx), (parts), (tzoffset), (flags)) +#else +/* No provider for DUK_USE_DATE_FORMAT_STRING(), fall back to ISO 8601 only. */ +#endif + +#endif /* DUK_COMPILING_DUKTAPE */ + +/* + * Checks for legacy feature options (DUK_OPT_xxx) + */ + +#if defined(DUK_OPT_ASSERTIONS) +#error unsupported legacy feature option DUK_OPT_ASSERTIONS used, consider options: DUK_USE_ASSERTIONS +#endif +#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT) +#error unsupported legacy feature option DUK_OPT_BUFFEROBJECT_SUPPORT used +#endif +#if defined(DUK_OPT_BUFLEN16) +#error unsupported legacy feature option DUK_OPT_BUFLEN16 used +#endif +#if defined(DUK_OPT_DATAPTR16) +#error unsupported legacy feature option DUK_OPT_DATAPTR16 used +#endif +#if defined(DUK_OPT_DATAPTR_DEC16) +#error unsupported legacy feature option DUK_OPT_DATAPTR_DEC16 used +#endif +#if defined(DUK_OPT_DATAPTR_ENC16) +#error unsupported legacy feature option DUK_OPT_DATAPTR_ENC16 used +#endif +#if defined(DUK_OPT_DDDPRINT) +#error unsupported legacy feature option DUK_OPT_DDDPRINT used +#endif +#if defined(DUK_OPT_DDPRINT) +#error unsupported legacy feature option DUK_OPT_DDPRINT used +#endif +#if defined(DUK_OPT_DEBUG) +#error unsupported legacy feature option DUK_OPT_DEBUG used +#endif +#if defined(DUK_OPT_DEBUGGER_DUMPHEAP) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_DUMPHEAP used +#endif +#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_LOGGING used +#endif +#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_PRINTALERT used +#endif +#if defined(DUK_OPT_DEBUGGER_SUPPORT) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_SUPPORT used +#endif +#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_TRANSPORT_TORTURE used +#endif +#if defined(DUK_OPT_DEBUG_BUFSIZE) +#error unsupported legacy feature option DUK_OPT_DEBUG_BUFSIZE used +#endif +#if defined(DUK_OPT_DECLARE) +#error unsupported legacy feature option DUK_OPT_DECLARE used +#endif +#if defined(DUK_OPT_DEEP_C_STACK) +#error unsupported legacy feature option DUK_OPT_DEEP_C_STACK used +#endif +#if defined(DUK_OPT_DLL_BUILD) +#error unsupported legacy feature option DUK_OPT_DLL_BUILD used +#endif +#if defined(DUK_OPT_DPRINT) +#error unsupported legacy feature option DUK_OPT_DPRINT used +#endif +#if defined(DUK_OPT_DPRINT_COLORS) +#error unsupported legacy feature option DUK_OPT_DPRINT_COLORS used +#endif +#if defined(DUK_OPT_DPRINT_RDTSC) +#error unsupported legacy feature option DUK_OPT_DPRINT_RDTSC used +#endif +#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK) +#error unsupported legacy feature option DUK_OPT_EXEC_TIMEOUT_CHECK used +#endif +#if defined(DUK_OPT_EXTERNAL_STRINGS) +#error unsupported legacy feature option DUK_OPT_EXTERNAL_STRINGS used, consider options: DUK_USE_HSTRING_EXTDATA +#endif +#if defined(DUK_OPT_EXTSTR_FREE) +#error unsupported legacy feature option DUK_OPT_EXTSTR_FREE used +#endif +#if defined(DUK_OPT_EXTSTR_INTERN_CHECK) +#error unsupported legacy feature option DUK_OPT_EXTSTR_INTERN_CHECK used +#endif +#if defined(DUK_OPT_FASTINT) +#error unsupported legacy feature option DUK_OPT_FASTINT used, consider options: DUK_USE_FASTINT +#endif +#if defined(DUK_OPT_FORCE_ALIGN) +#error unsupported legacy feature option DUK_OPT_FORCE_ALIGN used +#endif +#if defined(DUK_OPT_FORCE_BYTEORDER) +#error unsupported legacy feature option DUK_OPT_FORCE_BYTEORDER used +#endif +#if defined(DUK_OPT_FUNCPTR16) +#error unsupported legacy feature option DUK_OPT_FUNCPTR16 used +#endif +#if defined(DUK_OPT_FUNCPTR_DEC16) +#error unsupported legacy feature option DUK_OPT_FUNCPTR_DEC16 used +#endif +#if defined(DUK_OPT_FUNCPTR_ENC16) +#error unsupported legacy feature option DUK_OPT_FUNCPTR_ENC16 used +#endif +#if defined(DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY) +#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY used +#endif +#if defined(DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY) +#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY used +#endif +#if defined(DUK_OPT_GC_TORTURE) +#error unsupported legacy feature option DUK_OPT_GC_TORTURE used +#endif +#if defined(DUK_OPT_HAVE_CUSTOM_H) +#error unsupported legacy feature option DUK_OPT_HAVE_CUSTOM_H used +#endif +#if defined(DUK_OPT_HEAPPTR16) +#error unsupported legacy feature option DUK_OPT_HEAPPTR16 used +#endif +#if defined(DUK_OPT_HEAPPTR_DEC16) +#error unsupported legacy feature option DUK_OPT_HEAPPTR_DEC16 used +#endif +#if defined(DUK_OPT_HEAPPTR_ENC16) +#error unsupported legacy feature option DUK_OPT_HEAPPTR_ENC16 used +#endif +#if defined(DUK_OPT_INTERRUPT_COUNTER) +#error unsupported legacy feature option DUK_OPT_INTERRUPT_COUNTER used +#endif +#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH) +#error unsupported legacy feature option DUK_OPT_JSON_STRINGIFY_FASTPATH used +#endif +#if defined(DUK_OPT_LIGHTFUNC_BUILTINS) +#error unsupported legacy feature option DUK_OPT_LIGHTFUNC_BUILTINS used +#endif +#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY used +#endif +#if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY used +#endif +#if defined(DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT) +#error unsupported legacy feature option DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT used +#endif +#if defined(DUK_OPT_NO_AUGMENT_ERRORS) +#error unsupported legacy feature option DUK_OPT_NO_AUGMENT_ERRORS used +#endif +#if defined(DUK_OPT_NO_BROWSER_LIKE) +#error unsupported legacy feature option DUK_OPT_NO_BROWSER_LIKE used +#endif +#if defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_BUFFEROBJECT_SUPPORT used +#endif +#if defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_BYTECODE_DUMP_SUPPORT used, consider options: DUK_USE_BYTECODE_DUMP_SUPPORT +#endif +#if defined(DUK_OPT_NO_COMMONJS_MODULES) +#error unsupported legacy feature option DUK_OPT_NO_COMMONJS_MODULES used +#endif +#if defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY used +#endif +#if defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF) +#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF used +#endif +#if defined(DUK_OPT_NO_ES6_PROXY) +#error unsupported legacy feature option DUK_OPT_NO_ES6_PROXY used +#endif +#if defined(DUK_OPT_NO_FILE_IO) +#error unsupported legacy feature option DUK_OPT_NO_FILE_IO used, consider options: DUK_USE_FILE_IO +#endif +#if defined(DUK_OPT_NO_FUNC_STMT) +#error unsupported legacy feature option DUK_OPT_NO_FUNC_STMT used +#endif +#if defined(DUK_OPT_NO_JC) +#error unsupported legacy feature option DUK_OPT_NO_JC used +#endif +#if defined(DUK_OPT_NO_JSONC) +#error unsupported legacy feature option DUK_OPT_NO_JSONC used +#endif +#if defined(DUK_OPT_NO_JSONX) +#error unsupported legacy feature option DUK_OPT_NO_JSONX used +#endif +#if defined(DUK_OPT_NO_JX) +#error unsupported legacy feature option DUK_OPT_NO_JX used +#endif +#if defined(DUK_OPT_NO_MARK_AND_SWEEP) +#error unsupported legacy feature option DUK_OPT_NO_MARK_AND_SWEEP used +#endif +#if defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE) +#error unsupported legacy feature option DUK_OPT_NO_MS_STRINGTABLE_RESIZE used +#endif +#if defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT used +#endif +#if defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER used +#endif +#if defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER used +#endif +#if defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT used +#endif +#if defined(DUK_OPT_NO_NONSTD_FUNC_STMT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_FUNC_STMT used +#endif +#if defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029 used +#endif +#if defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT used +#endif +#if defined(DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY used +#endif +#if defined(DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF) +#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF used +#endif +#if defined(DUK_OPT_NO_OCTAL_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_OCTAL_SUPPORT used +#endif +#if defined(DUK_OPT_NO_PACKED_TVAL) +#error unsupported legacy feature option DUK_OPT_NO_PACKED_TVAL used +#endif +#if defined(DUK_OPT_NO_PC2LINE) +#error unsupported legacy feature option DUK_OPT_NO_PC2LINE used +#endif +#if defined(DUK_OPT_NO_REFERENCE_COUNTING) +#error unsupported legacy feature option DUK_OPT_NO_REFERENCE_COUNTING used, consider options: DUK_USE_REFERENCE_COUNTING +#endif +#if defined(DUK_OPT_NO_REGEXP_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_REGEXP_SUPPORT used +#endif +#if defined(DUK_OPT_NO_SECTION_B) +#error unsupported legacy feature option DUK_OPT_NO_SECTION_B used +#endif +#if defined(DUK_OPT_NO_SOURCE_NONBMP) +#error unsupported legacy feature option DUK_OPT_NO_SOURCE_NONBMP used +#endif +#if defined(DUK_OPT_NO_STRICT_DECL) +#error unsupported legacy feature option DUK_OPT_NO_STRICT_DECL used +#endif +#if defined(DUK_OPT_NO_TRACEBACKS) +#error unsupported legacy feature option DUK_OPT_NO_TRACEBACKS used +#endif +#if defined(DUK_OPT_NO_VERBOSE_ERRORS) +#error unsupported legacy feature option DUK_OPT_NO_VERBOSE_ERRORS used +#endif +#if defined(DUK_OPT_NO_VOLUNTARY_GC) +#error unsupported legacy feature option DUK_OPT_NO_VOLUNTARY_GC used +#endif +#if defined(DUK_OPT_NO_ZERO_BUFFER_DATA) +#error unsupported legacy feature option DUK_OPT_NO_ZERO_BUFFER_DATA used +#endif +#if defined(DUK_OPT_OBJSIZES16) +#error unsupported legacy feature option DUK_OPT_OBJSIZES16 used +#endif +#if defined(DUK_OPT_PANIC_HANDLER) +#error unsupported legacy feature option DUK_OPT_PANIC_HANDLER used +#endif +#if defined(DUK_OPT_REFCOUNT16) +#error unsupported legacy feature option DUK_OPT_REFCOUNT16 used +#endif +#if defined(DUK_OPT_SEGFAULT_ON_PANIC) +#error unsupported legacy feature option DUK_OPT_SEGFAULT_ON_PANIC used +#endif +#if defined(DUK_OPT_SELF_TESTS) +#error unsupported legacy feature option DUK_OPT_SELF_TESTS used +#endif +#if defined(DUK_OPT_SETJMP) +#error unsupported legacy feature option DUK_OPT_SETJMP used +#endif +#if defined(DUK_OPT_SHUFFLE_TORTURE) +#error unsupported legacy feature option DUK_OPT_SHUFFLE_TORTURE used +#endif +#if defined(DUK_OPT_SIGSETJMP) +#error unsupported legacy feature option DUK_OPT_SIGSETJMP used +#endif +#if defined(DUK_OPT_STRHASH16) +#error unsupported legacy feature option DUK_OPT_STRHASH16 used +#endif +#if defined(DUK_OPT_STRICT_UTF8_SOURCE) +#error unsupported legacy feature option DUK_OPT_STRICT_UTF8_SOURCE used +#endif +#if defined(DUK_OPT_STRLEN16) +#error unsupported legacy feature option DUK_OPT_STRLEN16 used +#endif +#if defined(DUK_OPT_STRTAB_CHAIN) +#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN used +#endif +#if defined(DUK_OPT_STRTAB_CHAIN_SIZE) +#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN_SIZE used +#endif +#if defined(DUK_OPT_TARGET_INFO) +#error unsupported legacy feature option DUK_OPT_TARGET_INFO used +#endif +#if defined(DUK_OPT_TRACEBACK_DEPTH) +#error unsupported legacy feature option DUK_OPT_TRACEBACK_DEPTH used +#endif +#if defined(DUK_OPT_UNDERSCORE_SETJMP) +#error unsupported legacy feature option DUK_OPT_UNDERSCORE_SETJMP used +#endif +#if defined(DUK_OPT_USER_INITJS) +#error unsupported legacy feature option DUK_OPT_USER_INITJS used +#endif + +/* + * Checks for config option consistency (DUK_USE_xxx) + */ + +#if defined(DUK_USE_32BIT_PTRS) +#error unsupported config option used (option has been removed): DUK_USE_32BIT_PTRS +#endif +#if defined(DUK_USE_ALIGN_4) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_4 +#endif +#if defined(DUK_USE_ALIGN_8) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8 +#endif +#if defined(DUK_USE_BYTEORDER_FORCED) +#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED +#endif +#if defined(DUK_USE_DATAPTR_DEC16) && !defined(DUK_USE_DATAPTR16) +#error config option DUK_USE_DATAPTR_DEC16 requires option DUK_USE_DATAPTR16 (which is missing) +#endif +#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16) +#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing) +#endif +#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER) +#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing) +#endif +#if defined(DUK_USE_DEEP_C_STACK) +#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK +#endif +#if defined(DUK_USE_DOUBLE_BE) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_BE +#endif +#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_LE) +#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_LE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_ME) +#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_LE) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_LE +#endif +#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_BE) +#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_BE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_ME) +#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_ME) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_ME +#endif +#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_LE) +#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_LE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_BE) +#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_BE (which is also defined) +#endif +#if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG) +#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing) +#endif +#if defined(DUK_USE_ESBC_MAX_BYTES) && !defined(DUK_USE_ESBC_LIMITS) +#error config option DUK_USE_ESBC_MAX_BYTES requires option DUK_USE_ESBC_LIMITS (which is missing) +#endif +#if defined(DUK_USE_ESBC_MAX_LINENUMBER) && !defined(DUK_USE_ESBC_LIMITS) +#error config option DUK_USE_ESBC_MAX_LINENUMBER requires option DUK_USE_ESBC_LIMITS (which is missing) +#endif +#if defined(DUK_USE_EXEC_TIMEOUT_CHECK) && !defined(DUK_USE_INTERRUPT_COUNTER) +#error config option DUK_USE_EXEC_TIMEOUT_CHECK requires option DUK_USE_INTERRUPT_COUNTER (which is missing) +#endif +#if defined(DUK_USE_EXTSTR_FREE) && !defined(DUK_USE_HSTRING_EXTDATA) +#error config option DUK_USE_EXTSTR_FREE requires option DUK_USE_HSTRING_EXTDATA (which is missing) +#endif +#if defined(DUK_USE_EXTSTR_INTERN_CHECK) && !defined(DUK_USE_HSTRING_EXTDATA) +#error config option DUK_USE_EXTSTR_INTERN_CHECK requires option DUK_USE_HSTRING_EXTDATA (which is missing) +#endif +#if defined(DUK_USE_FULL_TVAL) +#error unsupported config option used (option has been removed): DUK_USE_FULL_TVAL +#endif +#if defined(DUK_USE_FUNCPTR_DEC16) && !defined(DUK_USE_FUNCPTR16) +#error config option DUK_USE_FUNCPTR_DEC16 requires option DUK_USE_FUNCPTR16 (which is missing) +#endif +#if defined(DUK_USE_FUNCPTR_ENC16) && !defined(DUK_USE_FUNCPTR16) +#error config option DUK_USE_FUNCPTR_ENC16 requires option DUK_USE_FUNCPTR16 (which is missing) +#endif +#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS) +#error unsupported config option used (option has been removed): DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS +#endif +#if defined(DUK_USE_HEAPPTR16) && defined(DUK_USE_DEBUG) +#error config option DUK_USE_HEAPPTR16 conflicts with option DUK_USE_DEBUG (which is also defined) +#endif +#if defined(DUK_USE_HEAPPTR_DEC16) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_HEAPPTR_DEC16 requires option DUK_USE_HEAPPTR16 (which is missing) +#endif +#if defined(DUK_USE_HEAPPTR_ENC16) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_HEAPPTR_ENC16 requires option DUK_USE_HEAPPTR16 (which is missing) +#endif +#if defined(DUK_USE_INTEGER_BE) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_BE +#endif +#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_LE) +#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_LE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_ME) +#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_ME (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_LE) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_LE +#endif +#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_BE) +#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_BE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_ME) +#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_ME (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_ME) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_ME +#endif +#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_LE) +#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_LE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE) +#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined) +#endif +#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST) +#error unsupported config option used (option has been removed): DUK_USE_NO_DOUBLE_ALIASING_SELFTEST +#endif +#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) +#error unsupported config option used (option has been removed): DUK_USE_PACKED_TVAL_POSSIBLE +#endif +#if defined(DUK_USE_RDTSC) +#error unsupported config option used (option has been removed): DUK_USE_RDTSC +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && defined(DUK_USE_ROM_GLOBAL_INHERIT) +#error config option DUK_USE_ROM_GLOBAL_CLONE conflicts with option DUK_USE_ROM_GLOBAL_INHERIT (which is also defined) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && defined(DUK_USE_ROM_GLOBAL_CLONE) +#error config option DUK_USE_ROM_GLOBAL_INHERIT conflicts with option DUK_USE_ROM_GLOBAL_CLONE (which is also defined) +#endif +#if defined(DUK_USE_ROM_OBJECTS) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_OBJECTS requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_STRINGS) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_STRINGS requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_SETJMP) +#error unsupported config option used (option has been removed): DUK_USE_SETJMP +#endif +#if defined(DUK_USE_SIGSETJMP) +#error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP +#endif +#if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN) +#error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing) +#endif +#if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) +#error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined) +#endif +#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) +#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE +#endif +#if defined(DUK_USE_UNDERSCORE_SETJMP) +#error unsupported config option used (option has been removed): DUK_USE_UNDERSCORE_SETJMP +#endif + +#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus) +#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler +#endif + +/* + * Convert DUK_USE_BYTEORDER, from whatever source, into currently used + * internal defines. If detection failed, #error out. + */ + +#if defined(DUK_USE_BYTEORDER) +#if (DUK_USE_BYTEORDER == 1) +#define DUK_USE_INTEGER_LE +#define DUK_USE_DOUBLE_LE +#elif (DUK_USE_BYTEORDER == 2) +#define DUK_USE_INTEGER_LE /* integer endianness is little on purpose */ +#define DUK_USE_DOUBLE_ME +#elif (DUK_USE_BYTEORDER == 3) +#define DUK_USE_INTEGER_BE +#define DUK_USE_DOUBLE_BE +#else +#error unsupported: byte order invalid +#endif /* byte order */ +#else +#error unsupported: byte order detection failed +#endif /* defined(DUK_USE_BYTEORDER) */ + +#endif /* DUK_CONFIG_H_INCLUDED */ diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/duk_config.h-modular-static b/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/duk_config.h-modular-static new file mode 100644 index 000000000..b2b5a38a4 --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/duk_config.h-modular-static @@ -0,0 +1,3415 @@ +/* + * duk_config.h configuration header generated by genconfig.py. + * + * Git commit: cad34ae155acb0846545ca6bf2d29f9463b22bbb + * Git describe: v1.5.2 + * Git branch: HEAD + * + * Supported platforms: + * - Mac OSX, iPhone, Darwin + * - OpenBSD + * - Generic BSD + * - Atari ST TOS + * - AmigaOS + * - Windows + * - Flashplayer (Crossbridge) + * - QNX + * - TI-Nspire + * - Emscripten + * - Linux + * - Solaris + * - Generic POSIX + * - Cygwin + * - Generic UNIX + * - Generic fallback + * + * Supported architectures: + * - x86 + * - x64 + * - x32 + * - ARM 32-bit + * - ARM 64-bit + * - MIPS 32-bit + * - MIPS 64-bit + * - PowerPC 32-bit + * - PowerPC 64-bit + * - SPARC 32-bit + * - SPARC 64-bit + * - SuperH + * - Motorola 68k + * - Emscripten + * - Generic + * + * Supported compilers: + * - Clang + * - GCC + * - MSVC + * - Emscripten + * - TinyC + * - VBCC + * - Bruce's C compiler + * - Generic + * + */ + +#if !defined(DUK_CONFIG_H_INCLUDED) +#define DUK_CONFIG_H_INCLUDED + +/* + * Intermediate helper defines + */ + +/* DLL build detection */ +#if defined(DUK_OPT_DLL_BUILD) +#define DUK_F_DLL_BUILD +#elif defined(DUK_OPT_NO_DLL_BUILD) +#undef DUK_F_DLL_BUILD +#else +/* not configured for DLL build */ +#undef DUK_F_DLL_BUILD +#endif + +/* Apple OSX, iOS */ +#if defined(__APPLE__) +#define DUK_F_APPLE +#endif + +/* OpenBSD */ +#if defined(__OpenBSD__) || defined(__OpenBSD) +#define DUK_F_OPENBSD +#endif + +/* NetBSD */ +#if defined(__NetBSD__) || defined(__NetBSD) +#define DUK_F_NETBSD +#endif + +/* FreeBSD */ +#if defined(__FreeBSD__) || defined(__FreeBSD) +#define DUK_F_FREEBSD +#endif + +/* BSD variant */ +#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ + defined(__bsdi__) || defined(__DragonFly__) +#define DUK_F_BSD +#endif + +/* Atari ST TOS. __TOS__ defined by PureC. No platform define in VBCC + * apparently, so to use with VBCC user must define __TOS__ manually. + */ +#if defined(__TOS__) +#define DUK_F_TOS +#endif + +/* Motorola 68K. Not defined by VBCC, so user must define one of these + * manually when using VBCC. + */ +#if defined(__m68k__) || defined(M68000) || defined(__MC68K__) +#define DUK_F_M68K +#endif + +/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must + * define 'AMIGA' manually when using VBCC. + */ +#if defined(AMIGA) || defined(__amigaos__) +#define DUK_F_AMIGAOS +#endif + +/* PowerPC */ +#if defined(__powerpc) || defined(__powerpc__) || defined(__PPC__) +#define DUK_F_PPC +#if defined(__PPC64__) || defined(__LP64__) || defined(_LP64) +#define DUK_F_PPC64 +#else +#define DUK_F_PPC32 +#endif +#endif + +/* Windows, both 32-bit and 64-bit */ +#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ + defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) +#define DUK_F_WINDOWS +#if defined(_WIN64) || defined(WIN64) +#define DUK_F_WIN64 +#else +#define DUK_F_WIN32 +#endif +#endif + +/* Flash player (e.g. Crossbridge) */ +#if defined(__FLASHPLAYER__) +#define DUK_F_FLASHPLAYER +#endif + +/* QNX */ +#if defined(__QNX__) +#define DUK_F_QNX +#endif + +/* TI-Nspire (using Ndless) */ +#if defined(_TINSPIRE) +#define DUK_F_TINSPIRE +#endif + +/* Emscripten (provided explicitly by user), improve if possible */ +#if defined(EMSCRIPTEN) +#define DUK_F_EMSCRIPTEN +#endif + +/* BCC (Bruce's C compiler): this is a "torture target" for compilation */ +#if defined(__BCC__) || defined(__BCC_VERSION__) +#define DUK_F_BCC +#endif + +/* Linux */ +#if defined(__linux) || defined(__linux__) || defined(linux) +#define DUK_F_LINUX +#endif + +/* illumos / Solaris */ +#if defined(__sun) && defined(__SVR4) +#define DUK_F_SUN +#endif + +/* POSIX */ +#if defined(__posix) +#define DUK_F_POSIX +#endif + +/* Cygwin */ +#if defined(__CYGWIN__) +#define DUK_F_CYGWIN +#endif + +/* Generic Unix (includes Cygwin) */ +#if defined(__unix) || defined(__unix__) || defined(unix) || \ + defined(DUK_F_LINUX) || defined(DUK_F_BSD) +#define DUK_F_UNIX +#endif + +/* stdint.h not available */ +#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) +#if (_MSC_VER < 1700) +/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ +#define DUK_F_NO_STDINT_H +#endif +#endif +#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC)) +#define DUK_F_NO_STDINT_H +#endif + +/* C++ */ +#undef DUK_F_CPP +#if defined(__cplusplus) +#define DUK_F_CPP +#endif + +/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), + * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. + * https://sites.google.com/site/x32abi/ + */ +#if defined(__amd64__) || defined(__amd64) || \ + defined(__x86_64__) || defined(__x86_64) || \ + defined(_M_X64) || defined(_M_AMD64) +#if defined(__ILP32__) || defined(_ILP32) +#define DUK_F_X32 +#else +#define DUK_F_X64 +#endif +#elif defined(i386) || defined(__i386) || defined(__i386__) || \ + defined(__i486__) || defined(__i586__) || defined(__i686__) || \ + defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \ + defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) +#if defined(__LP64__) || defined(_LP64) +/* This should not really happen, but would indicate x64. */ +#define DUK_F_X64 +#else +#define DUK_F_X86 +#endif +#endif + +/* ARM */ +#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) +#define DUK_F_ARM +#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) +#define DUK_F_ARM64 +#else +#define DUK_F_ARM32 +#endif +#endif + +/* MIPS. Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */ +#if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \ + defined(_R3000) || defined(_R4000) || defined(_R5900) || \ + defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \ + defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \ + defined(__mips) || defined(__MIPS__) +#define DUK_F_MIPS +#if defined(__LP64__) || defined(_LP64) || defined(__mips64) || \ + defined(__mips64__) || defined(__mips_n64) +#define DUK_F_MIPS64 +#else +#define DUK_F_MIPS32 +#endif +#endif + +/* SPARC */ +#if defined(sparc) || defined(__sparc) || defined(__sparc__) +#define DUK_F_SPARC +#if defined(__LP64__) || defined(_LP64) +#define DUK_F_SPARC64 +#else +#define DUK_F_SPARC32 +#endif +#endif + +/* SuperH */ +#if defined(__sh__) || \ + defined(__sh1__) || defined(__SH1__) || \ + defined(__sh2__) || defined(__SH2__) || \ + defined(__sh3__) || defined(__SH3__) || \ + defined(__sh4__) || defined(__SH4__) || \ + defined(__sh5__) || defined(__SH5__) +#define DUK_F_SUPERH +#endif + +/* Clang */ +#if defined(__clang__) +#define DUK_F_CLANG +#endif + +/* C99 or above */ +#undef DUK_F_C99 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define DUK_F_C99 +#endif + +/* C++11 or above */ +#undef DUK_F_CPP11 +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define DUK_F_CPP11 +#endif + +/* GCC. Clang also defines __GNUC__ so don't detect GCC if using Clang. */ +#if defined(__GNUC__) && !defined(__clang__) && !defined(DUK_F_CLANG) +#define DUK_F_GCC +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +/* Convenience, e.g. gcc 4.5.1 == 40501; http://stackoverflow.com/questions/6031819/emulating-gccs-builtin-unreachable */ +#define DUK_F_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__) +#else +#error cannot figure out gcc version +#endif +#endif + +/* MinGW. Also GCC flags (DUK_F_GCC) are enabled now. */ +#if defined(__MINGW32__) || defined(__MINGW64__) +#define DUK_F_MINGW +#endif + +/* MSVC */ +#if defined(_MSC_VER) +/* MSVC preprocessor defines: http://msdn.microsoft.com/en-us/library/b0084kay.aspx + * _MSC_FULL_VER includes the build number, but it has at least two formats, see e.g. + * BOOST_MSVC_FULL_VER in http://www.boost.org/doc/libs/1_52_0/boost/config/compiler/visualc.hpp + */ +#define DUK_F_MSVC +#if defined(_MSC_FULL_VER) +#if (_MSC_FULL_VER > 100000000) +#define DUK_F_MSVC_FULL_VER _MSC_FULL_VER +#else +#define DUK_F_MSCV_FULL_VER (_MSC_FULL_VER * 10) +#endif +#endif +#endif /* _MSC_VER */ + +/* TinyC */ +#if defined(__TINYC__) +/* http://bellard.org/tcc/tcc-doc.html#SEC9 */ +#define DUK_F_TINYC +#endif + +/* VBCC */ +#if defined(__VBCC__) +#define DUK_F_VBCC +#endif + +/* Atari Mint */ +#if defined(__MINT__) +#define DUK_F_MINT +#endif + +/* + * Platform autodetection + */ + +/* Workaround for older C++ compilers before including , + * see e.g.: https://sourceware.org/bugzilla/show_bug.cgi?id=15366 + */ +#if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS) +#define __STDC_LIMIT_MACROS +#endif +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) +#define __STDC_CONSTANT_MACROS +#endif + +#if defined(DUK_F_APPLE) +/* --- Mac OSX, iPhone, Darwin --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */ +#if TARGET_IPHONE_SIMULATOR +#define DUK_USE_OS_STRING "iphone-sim" +#elif TARGET_OS_IPHONE +#define DUK_USE_OS_STRING "iphone" +#elif TARGET_OS_MAC +#define DUK_USE_OS_STRING "osx" +#else +#define DUK_USE_OS_STRING "osx-unknown" +#endif + +/* Use _setjmp() on Apple by default, see GH-55. */ +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) +#elif defined(DUK_F_OPENBSD) +/* --- OpenBSD --- */ +/* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "openbsd" +#elif defined(DUK_F_BSD) +/* --- Generic BSD --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "bsd" +#elif defined(DUK_F_TOS) +/* --- Atari ST TOS --- */ +#define DUK_USE_DATE_NOW_TIME +#define DUK_USE_DATE_TZO_GMTIME +/* no parsing (not an error) */ +#define DUK_USE_DATE_FMT_STRFTIME +#include + +#define DUK_USE_OS_STRING "tos" + +/* TOS on M68K is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_M68K) +#define DUK_USE_BYTEORDER 3 +#endif +#elif defined(DUK_F_AMIGAOS) +/* --- AmigaOS --- */ +#if defined(DUK_F_M68K) +/* AmigaOS on M68k */ +#define DUK_USE_DATE_NOW_TIME +#define DUK_USE_DATE_TZO_GMTIME +/* no parsing (not an error) */ +#define DUK_USE_DATE_FMT_STRFTIME +#include +#elif defined(DUK_F_PPC) +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#ifndef UINTPTR_MAX +#define UINTPTR_MAX UINT_MAX +#endif +#else +#error AmigaOS but not M68K/PPC, not supported now +#endif + +#define DUK_USE_OS_STRING "amigaos" + +/* AmigaOS on M68K or PPC is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) +#define DUK_USE_BYTEORDER 3 +#endif +#elif defined(DUK_F_WINDOWS) +/* --- Windows --- */ +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* Windows 32-bit and 64-bit are currently the same. */ +/* MSVC does not have sys/param.h */ +#define DUK_USE_DATE_NOW_WINDOWS +#define DUK_USE_DATE_TZO_WINDOWS +/* Note: PRS and FMT are intentionally left undefined for now. This means + * there is no platform specific date parsing/formatting but there is still + * the ISO 8601 standard format. + */ +#if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ +#include +#endif + +#define DUK_USE_OS_STRING "windows" + +/* On Windows, assume we're little endian. Even Itanium which has a + * configurable endianness runs little endian in Windows. + */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#elif defined(DUK_F_FLASHPLAYER) +/* --- Flashplayer (Crossbridge) --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "flashplayer" + +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_FLASHPLAYER) +#define DUK_USE_BYTEORDER 1 +#endif +#elif defined(DUK_F_QNX) +/* --- QNX --- */ +#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE) +/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */ +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L +#endif + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "qnx" +#elif defined(DUK_F_TINSPIRE) +/* --- TI-Nspire --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "tinspire" +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include +#if defined(DUK_F_BCC) +/* no endian.h */ +#else +#include +#endif /* DUK_F_BCC */ +#include +#include +#include +#include + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#define DUK_USE_OS_STRING "emscripten" +#elif defined(DUK_F_LINUX) +/* --- Linux --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include +#if defined(DUK_F_BCC) +/* no endian.h or stdint.h */ +#else +#include +#include +#endif /* DUK_F_BCC */ +#include +#include +#include + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#define DUK_USE_OS_STRING "linux" +#elif defined(DUK_F_SUN) +/* --- Solaris --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "solaris" +#elif defined(DUK_F_POSIX) +/* --- Generic POSIX --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "posix" +#elif defined(DUK_F_CYGWIN) +/* --- Cygwin --- */ +/* don't use strptime() for now */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) + +#define DUK_USE_OS_STRING "windows" +#elif defined(DUK_F_UNIX) +/* --- Generic UNIX --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#define DUK_USE_OS_STRING "unknown" +#else +/* --- Generic fallback --- */ +/* The most portable current time provider is time(), but it only has a + * one second resolution. + */ +#define DUK_USE_DATE_NOW_TIME + +/* The most portable way to figure out local time offset is gmtime(), + * but it's not thread safe so use with caution. + */ +#define DUK_USE_DATE_TZO_GMTIME + +/* Avoid custom date parsing and formatting for portability. */ +#undef DUK_USE_DATE_PRS_STRPTIME +#undef DUK_USE_DATE_FMT_STRFTIME + +/* Rely on C89 headers only; time.h must be here. */ +#include + +#define DUK_USE_OS_STRING "unknown" +#endif /* autodetect platform */ + +/* Shared includes: C89 */ +#include +#include +#include +#include /* varargs */ +#include +#include /* e.g. ptrdiff_t */ +#include +#include + +/* date.h is omitted, and included per platform */ + +/* Shared includes: stdint.h is C99 */ +#if defined(DUK_F_NO_STDINT_H) +/* stdint.h not available */ +#else +/* Technically C99 (C++11) but found in many systems. On some systems + * __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS must be defined before + * including stdint.h (see above). + */ +#include +#endif + +#if defined(DUK_F_CPP) +#include /* std::exception */ +#endif + +/* + * Architecture autodetection + */ + +#if defined(DUK_F_X86) +/* --- x86 --- */ +#define DUK_USE_ARCH_STRING "x86" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X64) +/* --- x64 --- */ +#define DUK_USE_ARCH_STRING "x64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X32) +/* --- x32 --- */ +#define DUK_USE_ARCH_STRING "x32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM32) +/* --- ARM 32-bit --- */ +#define DUK_USE_ARCH_STRING "arm32" +/* Byte order varies, so rely on autodetect. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM64) +/* --- ARM 64-bit --- */ +#define DUK_USE_ARCH_STRING "arm64" +/* Byte order varies, so rely on autodetect. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS32) +/* --- MIPS 32-bit --- */ +#define DUK_USE_ARCH_STRING "mips32" +/* MIPS byte order varies so rely on autodetection. */ +/* Based on 'make checkalign' there are no alignment requirements on + * Linux MIPS except for doubles, which need align by 4. Alignment + * requirements vary based on target though. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS64) +/* --- MIPS 64-bit --- */ +#define DUK_USE_ARCH_STRING "mips64" +/* MIPS byte order varies so rely on autodetection. */ +/* Good default is a bit arbitrary because alignment requirements + * depend on target. See https://github.com/svaarala/duktape/issues/102. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC32) +/* --- PowerPC 32-bit --- */ +#define DUK_USE_ARCH_STRING "ppc32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC64) +/* --- PowerPC 64-bit --- */ +#define DUK_USE_ARCH_STRING "ppc64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC32) +/* --- SPARC 32-bit --- */ +#define DUK_USE_ARCH_STRING "sparc32" +/* SPARC byte order varies so rely on autodetection. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC64) +/* --- SPARC 64-bit --- */ +#define DUK_USE_ARCH_STRING "sparc64" +/* SPARC byte order varies so rely on autodetection. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SUPERH) +/* --- SuperH --- */ +#define DUK_USE_ARCH_STRING "sh" +/* Byte order varies, rely on autodetection. */ +/* Based on 'make checkalign' there are no alignment requirements on + * Linux SH4, but align by 4 is probably a good basic default. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_M68K) +/* --- Motorola 68k --- */ +#define DUK_USE_ARCH_STRING "m68k" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_USE_ARCH_STRING "emscripten" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#else +/* --- Generic --- */ +/* These are necessary wild guesses. */ +#define DUK_USE_ARCH_STRING "generic" +/* Rely on autodetection for byte order, alignment, and packed tval. */ +#endif /* autodetect architecture */ + +/* + * Compiler autodetection + */ + +#if defined(DUK_F_CLANG) +/* --- Clang --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* Clang: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#else +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "clang" +#else +#define DUK_USE_COMPILER_STRING "clang" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR +#elif defined(DUK_F_GCC) +/* --- GCC --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* GCC: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 20500L) +/* since gcc-2.5 */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* since gcc-4.5 */ +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif + +#define DUK_USE_BRANCH_HINTS +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* GCC: test not very accurate; enable only in relatively recent builds + * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html) + */ +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) +#endif + +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#elif defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40000) +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_MINGW) +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "mingw++" +#else +#define DUK_USE_COMPILER_STRING "mingw" +#endif +#else +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "g++" +#else +#define DUK_USE_COMPILER_STRING "gcc" +#endif +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__)) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40600) +#define DUK_USE_GCC_PRAGMAS +#else +#undef DUK_USE_GCC_PRAGMAS +#endif + +#define DUK_USE_PACK_GCC_ATTR +#elif defined(DUK_F_MSVC) +/* --- MSVC --- */ +/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */ +#define DUK_NORETURN(decl) __declspec(noreturn) decl + +/* XXX: DUK_UNREACHABLE for msvc? */ + +#undef DUK_USE_BRANCH_HINTS + +/* XXX: DUK_LIKELY, DUK_UNLIKELY for msvc? */ +/* XXX: DUK_NOINLINE, DUK_INLINE, DUK_ALWAYS_INLINE for msvc? */ + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "msvc++" +#else +#define DUK_USE_COMPILER_STRING "msvc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) +#define DUK_USE_VARIADIC_MACROS +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +/* VS2005+ should have variadic macros even when they're not C99. */ +#define DUK_USE_VARIADIC_MACROS +#endif + +#undef DUK_USE_UNION_INITIALIZERS +#if defined(_MSC_VER) && (_MSC_VER >= 1800) +/* VS2013+ supports union initializers but there's a bug involving union-inside-struct: + * https://connect.microsoft.com/VisualStudio/feedback/details/805981 + * The bug was fixed (at least) in VS2015 so check for VS2015 for now: + * https://blogs.msdn.microsoft.com/vcblog/2015/07/01/c-compiler-front-end-fixes-in-vs2015/ + * Manually tested using VS2013, CL reports 18.00.31101, so enable for VS2013 too. + */ +#define DUK_USE_UNION_INITIALIZERS +#endif + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS + +#define DUK_USE_PACK_MSVC_PRAGMA + +/* These have been tested from VS2008 onwards; may work in older VS versions + * too but not enabled by default. + */ +#if defined(_MSC_VER) && (_MSC_VER >= 1500) +#define DUK_NOINLINE __declspec(noinline) +#define DUK_INLINE __inline +#define DUK_ALWAYS_INLINE __forceinline +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) +#define DUK_SNPRINTF snprintf +#define DUK_VSNPRINTF vsnprintf +#else +/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does + * NOT NUL terminate on truncation, but Duktape code never assumes that. + * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 + */ +#define DUK_SNPRINTF _snprintf +#define DUK_VSNPRINTF _vsnprintf +#endif +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static + +#define DUK_USE_COMPILER_STRING "emscripten" + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR +#elif defined(DUK_F_TINYC) +/* --- TinyC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "tinyc++" +#else +#define DUK_USE_COMPILER_STRING "tinyc" +#endif + +/* http://bellard.org/tcc/tcc-doc.html#SEC7 */ +#define DUK_USE_VARIADIC_MACROS + +#define DUK_USE_UNION_INITIALIZERS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#elif defined(DUK_F_VBCC) +/* --- VBCC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "vbcc-c++" +#else +#define DUK_USE_COMPILER_STRING "vbcc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +/* VBCC supports C99 so check only for C99 for union initializer support. + * Designated union initializers would possibly work even without a C99 check. + */ +#undef DUK_USE_UNION_INITIALIZERS +#if defined(DUK_F_C99) +#define DUK_USE_UNION_INITIALIZERS +#endif + +#define DUK_USE_FLEX_ZEROSIZE +#define DUK_USE_PACK_DUMMY_MEMBER +#elif defined(DUK_F_BCC) +/* --- Bruce's C compiler --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "bcc++" +#else +#define DUK_USE_COMPILER_STRING "bcc" +#endif + +/* Most portable */ +#undef DUK_USE_VARIADIC_MACROS + +/* Most portable, wastes space */ +#undef DUK_USE_UNION_INITIALIZERS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER + +/* BCC, assume we're on x86. */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#else +/* --- Generic --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "generic-c++" +#else +#define DUK_USE_COMPILER_STRING "generic" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +/* C++ doesn't have standard designated union initializers ({ .foo = 1 }). */ +#undef DUK_USE_UNION_INITIALIZERS +#if defined(DUK_F_C99) +#define DUK_USE_UNION_INITIALIZERS +#endif + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#endif /* autodetect compiler */ + +/* uclibc */ +#if defined(__UCLIBC__) +#define DUK_F_UCLIBC +#endif + +/* + * Wrapper typedefs and constants for integer types, also sanity check types. + * + * C99 typedefs are quite good but not always available, and we want to avoid + * forcibly redefining the C99 typedefs. So, there are Duktape wrappers for + * all C99 typedefs and Duktape code should only use these typedefs. Type + * detection when C99 is not supported is best effort and may end up detecting + * some types incorrectly. + * + * Pointer sizes are a portability problem: pointers to different types may + * have a different size and function pointers are very difficult to manage + * portably. + * + * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types + * + * Note: there's an interesting corner case when trying to define minimum + * signed integer value constants which leads to the current workaround of + * defining e.g. -0x80000000 as (-0x7fffffffL - 1L). See doc/code-issues.txt + * for a longer discussion. + * + * Note: avoid typecasts and computations in macro integer constants as they + * can then no longer be used in macro relational expressions (such as + * #if DUK_SIZE_MAX < 0xffffffffUL). There is internal code which relies on + * being able to compare DUK_SIZE_MAX against a limit. + */ + +/* XXX: add feature options to force basic types from outside? */ + +#if !defined(INT_MAX) +#error INT_MAX not defined +#endif + +/* Check that architecture is two's complement, standard C allows e.g. + * INT_MIN to be -2**31+1 (instead of -2**31). + */ +#if defined(INT_MAX) && defined(INT_MIN) +#if INT_MAX != -(INT_MIN + 1) +#error platform does not seem complement of two +#endif +#else +#error cannot check complement of two +#endif + +/* Pointer size determination based on __WORDSIZE or architecture when + * that's not available. + */ +#if defined(DUK_F_X86) || defined(DUK_F_X32) || \ + defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ + defined(DUK_F_BCC) || \ + (defined(__WORDSIZE) && (__WORDSIZE == 32)) +#define DUK_F_32BIT_PTRS +#elif defined(DUK_F_X64) || \ + (defined(__WORDSIZE) && (__WORDSIZE == 64)) +#define DUK_F_64BIT_PTRS +#else +/* not sure, not needed with C99 anyway */ +#endif + +/* Intermediate define for 'have inttypes.h' */ +#undef DUK_F_HAVE_INTTYPES +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !(defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)) +/* vbcc + AmigaOS has C99 but no inttypes.h */ +#define DUK_F_HAVE_INTTYPES +#elif defined(__cplusplus) && (__cplusplus >= 201103L) +/* C++11 apparently ratified stdint.h */ +#define DUK_F_HAVE_INTTYPES +#endif + +/* Basic integer typedefs and limits, preferably from inttypes.h, otherwise + * through automatic detection. + */ +#if defined(DUK_F_HAVE_INTTYPES) +/* C99 or compatible */ + +#define DUK_F_HAVE_64BIT +#include + +typedef uint8_t duk_uint8_t; +typedef int8_t duk_int8_t; +typedef uint16_t duk_uint16_t; +typedef int16_t duk_int16_t; +typedef uint32_t duk_uint32_t; +typedef int32_t duk_int32_t; +typedef uint64_t duk_uint64_t; +typedef int64_t duk_int64_t; +typedef uint_least8_t duk_uint_least8_t; +typedef int_least8_t duk_int_least8_t; +typedef uint_least16_t duk_uint_least16_t; +typedef int_least16_t duk_int_least16_t; +typedef uint_least32_t duk_uint_least32_t; +typedef int_least32_t duk_int_least32_t; +typedef uint_least64_t duk_uint_least64_t; +typedef int_least64_t duk_int_least64_t; +typedef uint_fast8_t duk_uint_fast8_t; +typedef int_fast8_t duk_int_fast8_t; +typedef uint_fast16_t duk_uint_fast16_t; +typedef int_fast16_t duk_int_fast16_t; +typedef uint_fast32_t duk_uint_fast32_t; +typedef int_fast32_t duk_int_fast32_t; +typedef uint_fast64_t duk_uint_fast64_t; +typedef int_fast64_t duk_int_fast64_t; +typedef uintptr_t duk_uintptr_t; +typedef intptr_t duk_intptr_t; +typedef uintmax_t duk_uintmax_t; +typedef intmax_t duk_intmax_t; + +#define DUK_UINT8_MIN 0 +#define DUK_UINT8_MAX UINT8_MAX +#define DUK_INT8_MIN INT8_MIN +#define DUK_INT8_MAX INT8_MAX +#define DUK_UINT_LEAST8_MIN 0 +#define DUK_UINT_LEAST8_MAX UINT_LEAST8_MAX +#define DUK_INT_LEAST8_MIN INT_LEAST8_MIN +#define DUK_INT_LEAST8_MAX INT_LEAST8_MAX +#define DUK_UINT_FAST8_MIN 0 +#define DUK_UINT_FAST8_MAX UINT_FAST8_MAX +#define DUK_INT_FAST8_MIN INT_FAST8_MIN +#define DUK_INT_FAST8_MAX INT_FAST8_MAX +#define DUK_UINT16_MIN 0 +#define DUK_UINT16_MAX UINT16_MAX +#define DUK_INT16_MIN INT16_MIN +#define DUK_INT16_MAX INT16_MAX +#define DUK_UINT_LEAST16_MIN 0 +#define DUK_UINT_LEAST16_MAX UINT_LEAST16_MAX +#define DUK_INT_LEAST16_MIN INT_LEAST16_MIN +#define DUK_INT_LEAST16_MAX INT_LEAST16_MAX +#define DUK_UINT_FAST16_MIN 0 +#define DUK_UINT_FAST16_MAX UINT_FAST16_MAX +#define DUK_INT_FAST16_MIN INT_FAST16_MIN +#define DUK_INT_FAST16_MAX INT_FAST16_MAX +#define DUK_UINT32_MIN 0 +#define DUK_UINT32_MAX UINT32_MAX +#define DUK_INT32_MIN INT32_MIN +#define DUK_INT32_MAX INT32_MAX +#define DUK_UINT_LEAST32_MIN 0 +#define DUK_UINT_LEAST32_MAX UINT_LEAST32_MAX +#define DUK_INT_LEAST32_MIN INT_LEAST32_MIN +#define DUK_INT_LEAST32_MAX INT_LEAST32_MAX +#define DUK_UINT_FAST32_MIN 0 +#define DUK_UINT_FAST32_MAX UINT_FAST32_MAX +#define DUK_INT_FAST32_MIN INT_FAST32_MIN +#define DUK_INT_FAST32_MAX INT_FAST32_MAX +#define DUK_UINT64_MIN 0 +#define DUK_UINT64_MAX UINT64_MAX +#define DUK_INT64_MIN INT64_MIN +#define DUK_INT64_MAX INT64_MAX +#define DUK_UINT_LEAST64_MIN 0 +#define DUK_UINT_LEAST64_MAX UINT_LEAST64_MAX +#define DUK_INT_LEAST64_MIN INT_LEAST64_MIN +#define DUK_INT_LEAST64_MAX INT_LEAST64_MAX +#define DUK_UINT_FAST64_MIN 0 +#define DUK_UINT_FAST64_MAX UINT_FAST64_MAX +#define DUK_INT_FAST64_MIN INT_FAST64_MIN +#define DUK_INT_FAST64_MAX INT_FAST64_MAX + +#define DUK_UINTPTR_MIN 0 +#define DUK_UINTPTR_MAX UINTPTR_MAX +#define DUK_INTPTR_MIN INTPTR_MIN +#define DUK_INTPTR_MAX INTPTR_MAX + +#define DUK_UINTMAX_MIN 0 +#define DUK_UINTMAX_MAX UINTMAX_MAX +#define DUK_INTMAX_MIN INTMAX_MIN +#define DUK_INTMAX_MAX INTMAX_MAX + +#define DUK_SIZE_MIN 0 +#define DUK_SIZE_MAX SIZE_MAX +#undef DUK_SIZE_MAX_COMPUTED + +#else /* C99 types */ + +/* When C99 types are not available, we use heuristic detection to get + * the basic 8, 16, 32, and (possibly) 64 bit types. The fast/least + * types are then assumed to be exactly the same for now: these could + * be improved per platform but C99 types are very often now available. + * 64-bit types are not available on all platforms; this is OK at least + * on 32-bit platforms. + * + * This detection code is necessarily a bit hacky and can provide typedefs + * and defines that won't work correctly on some exotic platform. + */ + +#if (defined(CHAR_BIT) && (CHAR_BIT == 8)) || \ + (defined(UCHAR_MAX) && (UCHAR_MAX == 255)) +typedef unsigned char duk_uint8_t; +typedef signed char duk_int8_t; +#else +#error cannot detect 8-bit type +#endif + +#if defined(USHRT_MAX) && (USHRT_MAX == 65535UL) +typedef unsigned short duk_uint16_t; +typedef signed short duk_int16_t; +#elif defined(UINT_MAX) && (UINT_MAX == 65535UL) +/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ +typedef unsigned int duk_uint16_t; +typedef signed int duk_int16_t; +#else +#error cannot detect 16-bit type +#endif + +#if defined(UINT_MAX) && (UINT_MAX == 4294967295UL) +typedef unsigned int duk_uint32_t; +typedef signed int duk_int32_t; +#elif defined(ULONG_MAX) && (ULONG_MAX == 4294967295UL) +/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ +typedef unsigned long duk_uint32_t; +typedef signed long duk_int32_t; +#else +#error cannot detect 32-bit type +#endif + +/* 64-bit type detection is a bit tricky. + * + * ULLONG_MAX is a standard define. __LONG_LONG_MAX__ and __ULONG_LONG_MAX__ + * are used by at least GCC (even if system headers don't provide ULLONG_MAX). + * Some GCC variants may provide __LONG_LONG_MAX__ but not __ULONG_LONG_MAX__. + * + * ULL / LL constants are rejected / warned about by some compilers, even if + * the compiler has a 64-bit type and the compiler/system headers provide an + * unsupported constant (ULL/LL)! Try to avoid using ULL / LL constants. + * As a side effect we can only check that e.g. ULONG_MAX is larger than 32 + * bits but can't be sure it is exactly 64 bits. Self tests will catch such + * cases. + */ +#undef DUK_F_HAVE_64BIT +#if !defined(DUK_F_HAVE_64BIT) && defined(ULONG_MAX) +#if (ULONG_MAX > 4294967295UL) +#define DUK_F_HAVE_64BIT +typedef unsigned long duk_uint64_t; +typedef signed long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(ULLONG_MAX) +#if (ULLONG_MAX > 4294967295UL) +#define DUK_F_HAVE_64BIT +typedef unsigned long long duk_uint64_t; +typedef signed long long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(__ULONG_LONG_MAX__) +#if (__ULONG_LONG_MAX__ > 4294967295UL) +#define DUK_F_HAVE_64BIT +typedef unsigned long long duk_uint64_t; +typedef signed long long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && defined(__LONG_LONG_MAX__) +#if (__LONG_LONG_MAX__ > 2147483647L) +#define DUK_F_HAVE_64BIT +typedef unsigned long long duk_uint64_t; +typedef signed long long duk_int64_t; +#endif +#endif +#if !defined(DUK_F_HAVE_64BIT) && \ + (defined(DUK_F_MINGW) || defined(DUK_F_MSVC)) +/* Both MinGW and MSVC have a 64-bit type. */ +#define DUK_F_HAVE_64BIT +typedef unsigned long duk_uint64_t; +typedef signed long duk_int64_t; +#endif +#if !defined(DUK_F_HAVE_64BIT) +/* cannot detect 64-bit type, not always needed so don't error */ +#endif + +typedef duk_uint8_t duk_uint_least8_t; +typedef duk_int8_t duk_int_least8_t; +typedef duk_uint16_t duk_uint_least16_t; +typedef duk_int16_t duk_int_least16_t; +typedef duk_uint32_t duk_uint_least32_t; +typedef duk_int32_t duk_int_least32_t; +typedef duk_uint8_t duk_uint_fast8_t; +typedef duk_int8_t duk_int_fast8_t; +typedef duk_uint16_t duk_uint_fast16_t; +typedef duk_int16_t duk_int_fast16_t; +typedef duk_uint32_t duk_uint_fast32_t; +typedef duk_int32_t duk_int_fast32_t; +#if defined(DUK_F_HAVE_64BIT) +typedef duk_uint64_t duk_uint_least64_t; +typedef duk_int64_t duk_int_least64_t; +typedef duk_uint64_t duk_uint_fast64_t; +typedef duk_int64_t duk_int_fast64_t; +#endif +#if defined(DUK_F_HAVE_64BIT) +typedef duk_uint64_t duk_uintmax_t; +typedef duk_int64_t duk_intmax_t; +#else +typedef duk_uint32_t duk_uintmax_t; +typedef duk_int32_t duk_intmax_t; +#endif + +/* Note: the funny looking computations for signed minimum 16-bit, 32-bit, and + * 64-bit values are intentional as the obvious forms (e.g. -0x80000000L) are + * -not- portable. See code-issues.txt for a detailed discussion. + */ +#define DUK_UINT8_MIN 0UL +#define DUK_UINT8_MAX 0xffUL +#define DUK_INT8_MIN (-0x80L) +#define DUK_INT8_MAX 0x7fL +#define DUK_UINT_LEAST8_MIN 0UL +#define DUK_UINT_LEAST8_MAX 0xffUL +#define DUK_INT_LEAST8_MIN (-0x80L) +#define DUK_INT_LEAST8_MAX 0x7fL +#define DUK_UINT_FAST8_MIN 0UL +#define DUK_UINT_FAST8_MAX 0xffUL +#define DUK_INT_FAST8_MIN (-0x80L) +#define DUK_INT_FAST8_MAX 0x7fL +#define DUK_UINT16_MIN 0UL +#define DUK_UINT16_MAX 0xffffUL +#define DUK_INT16_MIN (-0x7fffL - 1L) +#define DUK_INT16_MAX 0x7fffL +#define DUK_UINT_LEAST16_MIN 0UL +#define DUK_UINT_LEAST16_MAX 0xffffUL +#define DUK_INT_LEAST16_MIN (-0x7fffL - 1L) +#define DUK_INT_LEAST16_MAX 0x7fffL +#define DUK_UINT_FAST16_MIN 0UL +#define DUK_UINT_FAST16_MAX 0xffffUL +#define DUK_INT_FAST16_MIN (-0x7fffL - 1L) +#define DUK_INT_FAST16_MAX 0x7fffL +#define DUK_UINT32_MIN 0UL +#define DUK_UINT32_MAX 0xffffffffUL +#define DUK_INT32_MIN (-0x7fffffffL - 1L) +#define DUK_INT32_MAX 0x7fffffffL +#define DUK_UINT_LEAST32_MIN 0UL +#define DUK_UINT_LEAST32_MAX 0xffffffffUL +#define DUK_INT_LEAST32_MIN (-0x7fffffffL - 1L) +#define DUK_INT_LEAST32_MAX 0x7fffffffL +#define DUK_UINT_FAST32_MIN 0UL +#define DUK_UINT_FAST32_MAX 0xffffffffUL +#define DUK_INT_FAST32_MIN (-0x7fffffffL - 1L) +#define DUK_INT_FAST32_MAX 0x7fffffffL + +/* 64-bit constants. Since LL / ULL constants are not always available, + * use computed values. These values can't be used in preprocessor + * comparisons; flag them as such. + */ +#if defined(DUK_F_HAVE_64BIT) +#define DUK_UINT64_MIN ((duk_uint64_t) 0) +#define DUK_UINT64_MAX ((duk_uint64_t) -1) +#define DUK_INT64_MIN ((duk_int64_t) (~(DUK_UINT64_MAX >> 1))) +#define DUK_INT64_MAX ((duk_int64_t) (DUK_UINT64_MAX >> 1)) +#define DUK_UINT_LEAST64_MIN DUK_UINT64_MIN +#define DUK_UINT_LEAST64_MAX DUK_UINT64_MAX +#define DUK_INT_LEAST64_MIN DUK_INT64_MIN +#define DUK_INT_LEAST64_MAX DUK_INT64_MAX +#define DUK_UINT_FAST64_MIN DUK_UINT64_MIN +#define DUK_UINT_FAST64_MAX DUK_UINT64_MAX +#define DUK_INT_FAST64_MIN DUK_INT64_MIN +#define DUK_INT_FAST64_MAX DUK_INT64_MAX +#define DUK_UINT64_MIN_COMPUTED +#define DUK_UINT64_MAX_COMPUTED +#define DUK_INT64_MIN_COMPUTED +#define DUK_INT64_MAX_COMPUTED +#define DUK_UINT_LEAST64_MIN_COMPUTED +#define DUK_UINT_LEAST64_MAX_COMPUTED +#define DUK_INT_LEAST64_MIN_COMPUTED +#define DUK_INT_LEAST64_MAX_COMPUTED +#define DUK_UINT_FAST64_MIN_COMPUTED +#define DUK_UINT_FAST64_MAX_COMPUTED +#define DUK_INT_FAST64_MIN_COMPUTED +#define DUK_INT_FAST64_MAX_COMPUTED +#endif + +#if defined(DUK_F_HAVE_64BIT) +#define DUK_UINTMAX_MIN DUK_UINT64_MIN +#define DUK_UINTMAX_MAX DUK_UINT64_MAX +#define DUK_INTMAX_MIN DUK_INT64_MIN +#define DUK_INTMAX_MAX DUK_INT64_MAX +#define DUK_UINTMAX_MIN_COMPUTED +#define DUK_UINTMAX_MAX_COMPUTED +#define DUK_INTMAX_MIN_COMPUTED +#define DUK_INTMAX_MAX_COMPUTED +#else +#define DUK_UINTMAX_MIN 0UL +#define DUK_UINTMAX_MAX 0xffffffffUL +#define DUK_INTMAX_MIN (-0x7fffffffL - 1L) +#define DUK_INTMAX_MAX 0x7fffffffL +#endif + +/* This detection is not very reliable. */ +#if defined(DUK_F_32BIT_PTRS) +typedef duk_int32_t duk_intptr_t; +typedef duk_uint32_t duk_uintptr_t; +#define DUK_UINTPTR_MIN DUK_UINT32_MIN +#define DUK_UINTPTR_MAX DUK_UINT32_MAX +#define DUK_INTPTR_MIN DUK_INT32_MIN +#define DUK_INTPTR_MAX DUK_INT32_MAX +#elif defined(DUK_F_64BIT_PTRS) && defined(DUK_F_HAVE_64BIT) +typedef duk_int64_t duk_intptr_t; +typedef duk_uint64_t duk_uintptr_t; +#define DUK_UINTPTR_MIN DUK_UINT64_MIN +#define DUK_UINTPTR_MAX DUK_UINT64_MAX +#define DUK_INTPTR_MIN DUK_INT64_MIN +#define DUK_INTPTR_MAX DUK_INT64_MAX +#define DUK_UINTPTR_MIN_COMPUTED +#define DUK_UINTPTR_MAX_COMPUTED +#define DUK_INTPTR_MIN_COMPUTED +#define DUK_INTPTR_MAX_COMPUTED +#else +#error cannot determine intptr type +#endif + +/* SIZE_MAX may be missing so use an approximate value for it. */ +#undef DUK_SIZE_MAX_COMPUTED +#if !defined(SIZE_MAX) +#define DUK_SIZE_MAX_COMPUTED +#define SIZE_MAX ((size_t) (-1)) +#endif +#define DUK_SIZE_MIN 0 +#define DUK_SIZE_MAX SIZE_MAX + +#endif /* C99 types */ + +/* A few types are assumed to always exist. */ +typedef size_t duk_size_t; +typedef ptrdiff_t duk_ptrdiff_t; + +/* The best type for an "all around int" in Duktape internals is "at least + * 32 bit signed integer" which is most convenient. Same for unsigned type. + * Prefer 'int' when large enough, as it is almost always a convenient type. + */ +#if defined(UINT_MAX) && (UINT_MAX >= 0xffffffffUL) +typedef int duk_int_t; +typedef unsigned int duk_uint_t; +#define DUK_INT_MIN INT_MIN +#define DUK_INT_MAX INT_MAX +#define DUK_UINT_MIN 0 +#define DUK_UINT_MAX UINT_MAX +#else +typedef duk_int_fast32_t duk_int_t; +typedef duk_uint_fast32_t duk_uint_t; +#define DUK_INT_MIN DUK_INT_FAST32_MIN +#define DUK_INT_MAX DUK_INT_FAST32_MAX +#define DUK_UINT_MIN DUK_UINT_FAST32_MIN +#define DUK_UINT_MAX DUK_UINT_FAST32_MAX +#endif + +/* Same as 'duk_int_t' but guaranteed to be a 'fast' variant if this + * distinction matters for the CPU. These types are used mainly in the + * executor where it might really matter. + */ +typedef duk_int_fast32_t duk_int_fast_t; +typedef duk_uint_fast32_t duk_uint_fast_t; +#define DUK_INT_FAST_MIN DUK_INT_FAST32_MIN +#define DUK_INT_FAST_MAX DUK_INT_FAST32_MAX +#define DUK_UINT_FAST_MIN DUK_UINT_FAST32_MIN +#define DUK_UINT_FAST_MAX DUK_UINT_FAST32_MAX + +/* Small integers (16 bits or more) can fall back to the 'int' type, but + * have a typedef so they are marked "small" explicitly. + */ +typedef int duk_small_int_t; +typedef unsigned int duk_small_uint_t; +#define DUK_SMALL_INT_MIN INT_MIN +#define DUK_SMALL_INT_MAX INT_MAX +#define DUK_SMALL_UINT_MIN 0 +#define DUK_SMALL_UINT_MAX UINT_MAX + +/* Fast variants of small integers, again for really fast paths like the + * executor. + */ +typedef duk_int_fast16_t duk_small_int_fast_t; +typedef duk_uint_fast16_t duk_small_uint_fast_t; +#define DUK_SMALL_INT_FAST_MIN DUK_INT_FAST16_MIN +#define DUK_SMALL_INT_FAST_MAX DUK_INT_FAST16_MAX +#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN +#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX + +/* Boolean values are represented with the platform 'int'. */ +typedef duk_small_int_t duk_bool_t; +#define DUK_BOOL_MIN DUK_SMALL_INT_MIN +#define DUK_BOOL_MAX DUK_SMALL_INT_MAX + +/* Index values must have at least 32-bit signed range. */ +typedef duk_int_t duk_idx_t; +#define DUK_IDX_MIN DUK_INT_MIN +#define DUK_IDX_MAX DUK_INT_MAX + +/* Unsigned index variant. */ +typedef duk_uint_t duk_uidx_t; +#define DUK_UIDX_MIN DUK_UINT_MIN +#define DUK_UIDX_MAX DUK_UINT_MAX + +/* Array index values, could be exact 32 bits. + * Currently no need for signed duk_arridx_t. + */ +typedef duk_uint_t duk_uarridx_t; +#define DUK_UARRIDX_MIN DUK_UINT_MIN +#define DUK_UARRIDX_MAX DUK_UINT_MAX + +/* Duktape/C function return value, platform int is enough for now to + * represent 0, 1, or negative error code. Must be compatible with + * assigning truth values (e.g. duk_ret_t rc = (foo == bar);). + */ +typedef duk_small_int_t duk_ret_t; +#define DUK_RET_MIN DUK_SMALL_INT_MIN +#define DUK_RET_MAX DUK_SMALL_INT_MAX + +/* Error codes are represented with platform int. High bits are used + * for flags and such, so 32 bits are needed. + */ +typedef duk_int_t duk_errcode_t; +#define DUK_ERRCODE_MIN DUK_INT_MIN +#define DUK_ERRCODE_MAX DUK_INT_MAX + +/* Codepoint type. Must be 32 bits or more because it is used also for + * internal codepoints. The type is signed because negative codepoints + * are used as internal markers (e.g. to mark EOF or missing argument). + * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to + * ensure duk_uint32_t casts back and forth nicely. Almost everything + * else uses the signed one. + */ +typedef duk_int_t duk_codepoint_t; +typedef duk_uint_t duk_ucodepoint_t; +#define DUK_CODEPOINT_MIN DUK_INT_MIN +#define DUK_CODEPOINT_MAX DUK_INT_MAX +#define DUK_UCODEPOINT_MIN DUK_UINT_MIN +#define DUK_UCODEPOINT_MAX DUK_UINT_MAX + +/* IEEE float/double typedef. */ +typedef float duk_float_t; +typedef double duk_double_t; + +/* We're generally assuming that we're working on a platform with a 32-bit + * address space. If DUK_SIZE_MAX is a typecast value (which is necessary + * if SIZE_MAX is missing), the check must be avoided because the + * preprocessor can't do a comparison. + */ +#if !defined(DUK_SIZE_MAX) +#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX +#elif !defined(DUK_SIZE_MAX_COMPUTED) +#if DUK_SIZE_MAX < 0xffffffffUL +/* On some systems SIZE_MAX can be smaller than max unsigned 32-bit value + * which seems incorrect if size_t is (at least) an unsigned 32-bit type. + * However, it doesn't seem useful to error out compilation if this is the + * case. + */ +#endif +#endif + +/* Type for public API calls. */ +typedef struct duk_hthread duk_context; + +/* Check whether we should use 64-bit integers or not. + * + * Quite incomplete now. Use 64-bit types if detected (C99 or other detection) + * unless they are known to be unreliable. For instance, 64-bit types are + * available on VBCC but seem to misbehave. + */ +#if defined(DUK_F_HAVE_64BIT) && !defined(DUK_F_VBCC) +#define DUK_USE_64BIT_OPS +#else +#undef DUK_USE_64BIT_OPS +#endif + +/* + * Fill-ins for platform, architecture, and compiler + */ + +#if !defined(DUK_SETJMP) +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) setjmp((jb)) +#define DUK_LONGJMP(jb) longjmp((jb), 1) +#endif + +#if 0 +/* sigsetjmp() alternative */ +#define DUK_JMPBUF_TYPE sigjmp_buf +#define DUK_SETJMP(jb) sigsetjmp((jb)) +#define DUK_LONGJMP(jb) siglongjmp((jb), 1) +#endif + +typedef FILE duk_file; +#if !defined(DUK_STDIN) +#define DUK_STDIN stdin +#endif +#if !defined(DUK_STDOUT) +#define DUK_STDOUT stdout +#endif +#if !defined(DUK_STDERR) +#define DUK_STDERR stderr +#endif + +/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h + * (which is unfortunately named). May sometimes need replacement, e.g. + * some compilers don't handle zero length or NULL correctly in realloc(). + */ +#if !defined(DUK_ANSI_MALLOC) +#define DUK_ANSI_MALLOC malloc +#endif +#if !defined(DUK_ANSI_REALLOC) +#define DUK_ANSI_REALLOC realloc +#endif +#if !defined(DUK_ANSI_CALLOC) +#define DUK_ANSI_CALLOC calloc +#endif +#if !defined(DUK_ANSI_FREE) +#define DUK_ANSI_FREE free +#endif + +/* ANSI C (various versions) and some implementations require that the + * pointer arguments to memset(), memcpy(), and memmove() be valid values + * even when byte size is 0 (even a NULL pointer is considered invalid in + * this context). Zero-size operations as such are allowed, as long as their + * pointer arguments point to a valid memory area. The DUK_MEMSET(), + * DUK_MEMCPY(), and DUK_MEMMOVE() macros require this same behavior, i.e.: + * (1) pointers must be valid and non-NULL, (2) zero size must otherwise be + * allowed. If these are not fulfilled, a macro wrapper is needed. + * + * http://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0 + * http://lists.cs.uiuc.edu/pipermail/llvmdev/2007-October/011065.html + * + * Not sure what's the required behavior when a pointer points just past the + * end of a buffer, which often happens in practice (e.g. zero size memmoves). + * For example, if allocation size is 3, the following pointer would not + * technically point to a valid memory byte: + * + * <-- alloc --> + * | 0 | 1 | 2 | ..... + * ^-- p=3, points after last valid byte (2) + */ +#if !defined(DUK_MEMCPY) +#if defined(DUK_F_UCLIBC) +/* Old uclibcs have a broken memcpy so use memmove instead (this is overly wide + * now on purpose): http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html + */ +#define DUK_MEMCPY memmove +#else +#define DUK_MEMCPY memcpy +#endif +#endif +#if !defined(DUK_MEMMOVE) +#define DUK_MEMMOVE memmove +#endif +#if !defined(DUK_MEMCMP) +#define DUK_MEMCMP memcmp +#endif +#if !defined(DUK_MEMSET) +#define DUK_MEMSET memset +#endif +#if !defined(DUK_STRLEN) +#define DUK_STRLEN strlen +#endif +#if !defined(DUK_STRCMP) +#define DUK_STRCMP strcmp +#endif +#if !defined(DUK_STRNCMP) +#define DUK_STRNCMP strncmp +#endif +#if !defined(DUK_PRINTF) +#define DUK_PRINTF printf +#endif +#if !defined(DUK_FPRINTF) +#define DUK_FPRINTF fprintf +#endif +#if !defined(DUK_SPRINTF) +#define DUK_SPRINTF sprintf +#endif +#if !defined(DUK_SNPRINTF) +/* snprintf() is technically not part of C89 but usually available. */ +#define DUK_SNPRINTF snprintf +#endif +#if !defined(DUK_VSPRINTF) +#define DUK_VSPRINTF vsprintf +#endif +#if !defined(DUK_VSNPRINTF) +/* vsnprintf() is technically not part of C89 but usually available. */ +#define DUK_VSNPRINTF vsnprintf +#endif +#if !defined(DUK_SSCANF) +#define DUK_SSCANF sscanf +#endif +#if !defined(DUK_VSSCANF) +#define DUK_VSSCANF vsscanf +#endif +#if !defined(DUK_FOPEN) +#define DUK_FOPEN fopen +#endif +#if !defined(DUK_FCLOSE) +#define DUK_FCLOSE fclose +#endif +#if !defined(DUK_FREAD) +#define DUK_FREAD fread +#endif +#if !defined(DUK_FWRITE) +#define DUK_FWRITE fwrite +#endif +#if !defined(DUK_FSEEK) +#define DUK_FSEEK fseek +#endif +#if !defined(DUK_FTELL) +#define DUK_FTELL ftell +#endif +#if !defined(DUK_FFLUSH) +#define DUK_FFLUSH fflush +#endif +#if !defined(DUK_FPUTC) +#define DUK_FPUTC fputc +#endif +#if !defined(DUK_MEMZERO) +#define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n)) +#endif +#if !defined(DUK_ABORT) +#define DUK_ABORT abort +#endif +#if !defined(DUK_EXIT) +#define DUK_EXIT exit +#endif + +#if !defined(DUK_DOUBLE_2TO32) +#define DUK_DOUBLE_2TO32 4294967296.0 +#endif +#if !defined(DUK_DOUBLE_2TO31) +#define DUK_DOUBLE_2TO31 2147483648.0 +#endif + +#if !defined(DUK_DOUBLE_INFINITY) +#undef DUK_USE_COMPUTED_INFINITY +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION < 40600) +/* GCC older than 4.6: avoid overflow warnings related to using INFINITY */ +#define DUK_DOUBLE_INFINITY (__builtin_inf()) +#elif defined(INFINITY) +#define DUK_DOUBLE_INFINITY ((double) INFINITY) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#define DUK_DOUBLE_INFINITY (1.0 / 0.0) +#else +/* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. + * Use a computed infinity (initialized when a heap is created at the + * latest). + */ +#define DUK_USE_COMPUTED_INFINITY +#define DUK_DOUBLE_INFINITY duk_computed_infinity +#endif +#endif + +#if !defined(DUK_DOUBLE_NAN) +#undef DUK_USE_COMPUTED_NAN +#if defined(NAN) +#define DUK_DOUBLE_NAN NAN +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#define DUK_DOUBLE_NAN (0.0 / 0.0) +#else +/* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. + * In MSVC (VS2010 Express) (0.0 / 0.0) results in a compile error. + * Use a computed NaN (initialized when a heap is created at the + * latest). + */ +#define DUK_USE_COMPUTED_NAN +#define DUK_DOUBLE_NAN duk_computed_nan +#endif +#endif + +/* Many platforms are missing fpclassify() and friends, so use replacements + * if necessary. The replacement constants (FP_NAN etc) can be anything but + * match Linux constants now. + */ +#undef DUK_USE_REPL_FPCLASSIFY +#undef DUK_USE_REPL_SIGNBIT +#undef DUK_USE_REPL_ISFINITE +#undef DUK_USE_REPL_ISNAN +#undef DUK_USE_REPL_ISINF + +/* Complex condition broken into separate parts. */ +#undef DUK_F_USE_REPL_ALL +#if !(defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) && \ + defined(FP_SUBNORMAL) && defined(FP_NORMAL)) +/* Missing some obvious constants. */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC) +/* VBCC is missing the built-ins even in C99 mode (perhaps a header issue). */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_M68K) +/* AmigaOS + M68K seems to have math issues even when using GCC cross + * compilation. Use replacements for all AmigaOS versions on M68K + * regardless of compiler. + */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_FREEBSD) && defined(DUK_F_CLANG) +/* Placeholder fix for (detection is wider than necessary): + * http://llvm.org/bugs/show_bug.cgi?id=17788 + */ +#define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_UCLIBC) +/* At least some uclibc versions have broken floating point math. For + * example, fpclassify() can incorrectly classify certain NaN formats. + * To be safe, use replacements. + */ +#define DUK_F_USE_REPL_ALL +#endif + +#if defined(DUK_F_USE_REPL_ALL) +#define DUK_USE_REPL_FPCLASSIFY +#define DUK_USE_REPL_SIGNBIT +#define DUK_USE_REPL_ISFINITE +#define DUK_USE_REPL_ISNAN +#define DUK_USE_REPL_ISINF +#define DUK_FPCLASSIFY duk_repl_fpclassify +#define DUK_SIGNBIT duk_repl_signbit +#define DUK_ISFINITE duk_repl_isfinite +#define DUK_ISNAN duk_repl_isnan +#define DUK_ISINF duk_repl_isinf +#define DUK_FP_NAN 0 +#define DUK_FP_INFINITE 1 +#define DUK_FP_ZERO 2 +#define DUK_FP_SUBNORMAL 3 +#define DUK_FP_NORMAL 4 +#else +#define DUK_FPCLASSIFY fpclassify +#define DUK_SIGNBIT signbit +#define DUK_ISFINITE isfinite +#define DUK_ISNAN isnan +#define DUK_ISINF isinf +#define DUK_FP_NAN FP_NAN +#define DUK_FP_INFINITE FP_INFINITE +#define DUK_FP_ZERO FP_ZERO +#define DUK_FP_SUBNORMAL FP_SUBNORMAL +#define DUK_FP_NORMAL FP_NORMAL +#endif + +#if defined(DUK_F_USE_REPL_ALL) +#undef DUK_F_USE_REPL_ALL +#endif + +/* Some math functions are C99 only. This is also an issue with some + * embedded environments using uclibc where uclibc has been configured + * not to provide some functions. For now, use replacements whenever + * using uclibc. + */ +#undef DUK_USE_MATH_FMIN +#undef DUK_USE_MATH_FMAX +#undef DUK_USE_MATH_ROUND +#if defined(DUK_F_UCLIBC) +/* uclibc may be missing these */ +#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC) +/* vbcc + AmigaOS may be missing these */ +#elif defined(DUK_F_MINT) +/* mint clib is missing these */ +#elif !defined(DUK_F_C99) && !defined(DUK_F_CPP11) +/* build is not C99 or C++11, play it safe */ +#else +/* C99 or C++11, no known issues */ +#define DUK_USE_MATH_FMIN +#define DUK_USE_MATH_FMAX +#define DUK_USE_MATH_ROUND +#endif + +/* These functions don't currently need replacement but are wrapped for + * completeness. Because these are used as function pointers, they need + * to be defined as concrete C functions (not macros). + */ +#if !defined(DUK_FABS) +#define DUK_FABS fabs +#endif +#if !defined(DUK_FMIN) +#define DUK_FMIN fmin +#endif +#if !defined(DUK_FMAX) +#define DUK_FMAX fmax +#endif +#if !defined(DUK_FLOOR) +#define DUK_FLOOR floor +#endif +#if !defined(DUK_CEIL) +#define DUK_CEIL ceil +#endif +#if !defined(DUK_FMOD) +#define DUK_FMOD fmod +#endif +#if !defined(DUK_POW) +#define DUK_POW pow +#endif +#if !defined(DUK_ACOS) +#define DUK_ACOS acos +#endif +#if !defined(DUK_ASIN) +#define DUK_ASIN asin +#endif +#if !defined(DUK_ATAN) +#define DUK_ATAN atan +#endif +#if !defined(DUK_ATAN2) +#define DUK_ATAN2 atan2 +#endif +#if !defined(DUK_SIN) +#define DUK_SIN sin +#endif +#if !defined(DUK_COS) +#define DUK_COS cos +#endif +#if !defined(DUK_TAN) +#define DUK_TAN tan +#endif +#if !defined(DUK_EXP) +#define DUK_EXP exp +#endif +#if !defined(DUK_LOG) +#define DUK_LOG log +#endif +#if !defined(DUK_SQRT) +#define DUK_SQRT sqrt +#endif + +/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, + * see test-bug-netbsd-math-pow.js. Use NetBSD specific workaround. + * (This might be a wider problem; if so, generalize the define name.) + */ +#undef DUK_USE_POW_NETBSD_WORKAROUND +#if defined(DUK_F_NETBSD) +#define DUK_USE_POW_NETBSD_WORKAROUND +#endif + +/* Rely as little as possible on compiler behavior for NaN comparison, + * signed zero handling, etc. Currently never activated but may be needed + * for broken compilers. + */ +#undef DUK_USE_PARANOID_MATH + +/* There was a curious bug where test-bi-date-canceling.js would fail e.g. + * on 64-bit Ubuntu, gcc-4.8.1, -m32, and no -std=c99. Some date computations + * using doubles would be optimized which then broke some corner case tests. + * The problem goes away by adding 'volatile' to the datetime computations. + * Not sure what the actual triggering conditions are, but using this on + * non-C99 systems solves the known issues and has relatively little cost + * on other platforms. + */ +#undef DUK_USE_PARANOID_DATE_COMPUTATION +#if !defined(DUK_F_C99) +#define DUK_USE_PARANOID_DATE_COMPUTATION +#endif + +/* + * Byte order and double memory layout detection + * + * Endianness detection is a major portability hassle because the macros + * and headers are not standardized. There's even variance across UNIX + * platforms. Even with "standard" headers, details like underscore count + * varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used + * (Crossbridge has a single underscore, for instance). + * + * The checks below are structured with this in mind: several approaches are + * used, and at the end we check if any of them worked. This allows generic + * approaches to be tried first, and platform/compiler specific hacks tried + * last. As a last resort, the user can force a specific endianness, as it's + * not likely that automatic detection will work on the most exotic platforms. + * + * Duktape supports little and big endian machines. There's also support + * for a hybrid used by some ARM machines where integers are little endian + * but IEEE double values use a mixed order (12345678 -> 43218765). This + * byte order for doubles is referred to as "mixed endian". + */ + +/* For custom platforms allow user to define byteorder explicitly. + * Since endianness headers are not standardized, this is a useful + * workaround for custom platforms for which endianness detection + * is not directly supported. Perhaps custom hardware is used and + * user cannot submit upstream patches. + */ +#if defined(DUK_OPT_FORCE_BYTEORDER) +#undef DUK_USE_BYTEORDER +#if (DUK_OPT_FORCE_BYTEORDER == 1) +#define DUK_USE_BYTEORDER 1 +#elif (DUK_OPT_FORCE_BYTEORDER == 2) +#define DUK_USE_BYTEORDER 2 +#elif (DUK_OPT_FORCE_BYTEORDER == 3) +#define DUK_USE_BYTEORDER 3 +#else +#error invalid DUK_OPT_FORCE_BYTEORDER value +#endif +#endif /* DUK_OPT_FORCE_BYTEORDER */ + +/* GCC and Clang provide endianness defines as built-in predefines, with + * leading and trailing double underscores (e.g. __BYTE_ORDER__). See + * output of "make gccpredefs" and "make clangpredefs". Clang doesn't + * seem to provide __FLOAT_WORD_ORDER__; assume not mixed endian for clang. + * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html + */ +#if !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) +#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 +#else +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit + * integer ordering and is not relevant. + */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) */ + +/* More or less standard endianness predefines provided by header files. + * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER + * will be big endian, see: http://lists.mysql.com/internals/443. + * On some platforms some defines may be present with an empty value which + * causes comparisons to fail: https://github.com/svaarala/duktape/issues/453. + */ +#if !defined(DUK_USE_BYTEORDER) +#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \ + defined(__LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 +#else +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order. */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) */ + +/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__: + * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - > 24) | \ + ((((duk_uint32_t) (x)) >> 8) & 0xff00UL) | \ + ((((duk_uint32_t) (x)) << 8) & 0xff0000UL) | \ + (((duk_uint32_t) (x)) << 24)) +#endif +#if !defined(DUK_BSWAP16) +#define DUK_BSWAP16(x) \ + ((duk_uint16_t) (x) >> 8) | \ + ((duk_uint16_t) (x) << 8) +#endif + +/* DUK_USE_VARIADIC_MACROS: required from compilers, so no fill-in. */ +/* DUK_USE_UNION_INITIALIZERS: required from compilers, so no fill-in. */ + +#if !(defined(DUK_USE_FLEX_C99) || defined(DUK_USE_FLEX_ZEROSIZE) || defined(DUK_USE_FLEX_ONESIZE)) +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE /* Not standard but common enough */ +#endif +#endif + +#if !(defined(DUK_USE_PACK_GCC_ATTR) || defined(DUK_USE_PACK_CLANG_ATTR) || \ + defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_DUMMY_MEMBER)) +#define DUK_USE_PACK_DUMMY_MEMBER +#endif + +#if 0 /* not defined by default */ +#undef DUK_USE_GCC_PRAGMAS +#endif + +/* Workaround for GH-323: avoid inlining control when compiling from + * multiple sources, as it causes compiler portability trouble. + */ +#if !defined(DUK_SINGLE_FILE) +#undef DUK_NOINLINE +#undef DUK_INLINE +#undef DUK_ALWAYS_INLINE +#define DUK_NOINLINE /*nop*/ +#define DUK_INLINE /*nop*/ +#define DUK_ALWAYS_INLINE /*nop*/ +#endif + +/* + * Check whether or not a packed duk_tval representation is possible. + * What's basically required is that pointers are 32-bit values + * (sizeof(void *) == 4). Best effort check, not always accurate. + * If guess goes wrong, crashes may result; self tests also verify + * the guess. + */ + +/* Explicit marker needed; may be 'defined', 'undefined, 'or 'not provided'. */ +#if !defined(DUK_F_PACKED_TVAL_PROVIDED) +#undef DUK_F_PACKED_TVAL_POSSIBLE + +/* Strict C99 case: DUK_UINTPTR_MAX (= UINTPTR_MAX) should be very reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif + +/* Non-C99 case, still relying on DUK_UINTPTR_MAX, as long as it is not a computed value */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif + +/* DUK_SIZE_MAX (= SIZE_MAX) is often reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED) +#if (DUK_SIZE_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif + +#undef DUK_USE_PACKED_TVAL +#if defined(DUK_F_PACKED_TVAL_POSSIBLE) +#define DUK_USE_PACKED_TVAL +#endif + +#undef DUK_F_PACKED_TVAL_POSSIBLE +#endif /* DUK_F_PACKED_TVAL_PROVIDED */ + +/* Feature option forcing. */ +#if defined(DUK_OPT_NO_PACKED_TVAL) +#undef DUK_USE_PACKED_TVAL +#elif defined(DUK_OPT_PACKED_TVAL) +#undef DUK_USE_PACKED_TVAL +#define DUK_USE_PACKED_TVAL +#endif +/* Object property allocation layout has implications for memory and code + * footprint and generated code size/speed. The best layout also depends + * on whether the platform has alignment requirements or benefits from + * having mostly aligned accesses. + */ +#undef DUK_USE_HOBJECT_LAYOUT_1 +#undef DUK_USE_HOBJECT_LAYOUT_2 +#undef DUK_USE_HOBJECT_LAYOUT_3 +#if (DUK_USE_ALIGN_BY == 1) +/* On platforms without any alignment issues, layout 1 is preferable + * because it compiles to slightly less code and provides direct access + * to property keys. + */ +#define DUK_USE_HOBJECT_LAYOUT_1 +#else +/* On other platforms use layout 2, which requires some padding but + * is a bit more natural than layout 3 in ordering the entries. Layout + * 3 is currently not used. + */ +#define DUK_USE_HOBJECT_LAYOUT_2 +#endif + +/* GCC/clang inaccurate math would break compliance and probably duk_tval, + * so refuse to compile. Relax this if -ffast-math is tested to work. + */ +#if defined(__FAST_MATH__) +#error __FAST_MATH__ defined, refusing to compile +#endif + +/* + * Autogenerated defaults + */ + +#undef DUK_USE_ASSERTIONS +#define DUK_USE_AUGMENT_ERROR_CREATE +#define DUK_USE_AUGMENT_ERROR_THROW +#define DUK_USE_AVOID_PLATFORM_FUNCPTRS +#define DUK_USE_BASE64_FASTPATH +#define DUK_USE_BROWSER_LIKE +#define DUK_USE_BUFFEROBJECT_SUPPORT +#undef DUK_USE_BUFLEN16 +#define DUK_USE_BUILTIN_INITJS +#define DUK_USE_BYTECODE_DUMP_SUPPORT +#define DUK_USE_COMMONJS_MODULES +#define DUK_USE_COMPILER_RECLIMIT 2500 +#undef DUK_USE_CPP_EXCEPTIONS +#undef DUK_USE_DATAPTR16 +#undef DUK_USE_DATAPTR_DEC16 +#undef DUK_USE_DATAPTR_ENC16 +#undef DUK_USE_DATE_FORMAT_STRING +#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET +#undef DUK_USE_DATE_GET_NOW +#undef DUK_USE_DATE_PARSE_STRING +#undef DUK_USE_DATE_PRS_GETDATE +#undef DUK_USE_DDDPRINT +#undef DUK_USE_DDPRINT +#undef DUK_USE_DEBUG +#undef DUK_USE_DEBUGGER_DUMPHEAP +#undef DUK_USE_DEBUGGER_FWD_LOGGING +#undef DUK_USE_DEBUGGER_FWD_PRINTALERT +#undef DUK_USE_DEBUGGER_INSPECT +#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT +#undef DUK_USE_DEBUGGER_SUPPORT +#define DUK_USE_DEBUGGER_THROW_NOTIFY +#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE +#define DUK_USE_DEBUG_BUFSIZE 65536L +#define DUK_USE_DOUBLE_LINKED_HEAP +#undef DUK_USE_DPRINT +#undef DUK_USE_DPRINT_COLORS +#undef DUK_USE_DPRINT_RDTSC +#define DUK_USE_ERRCREATE +#define DUK_USE_ERRTHROW +#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY +#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF +#define DUK_USE_ES6_PROXY +#define DUK_USE_ES6_REGEXP_BRACES +#define DUK_USE_ESBC_LIMITS +#define DUK_USE_ESBC_MAX_BYTES 2147418112L +#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L +#undef DUK_USE_EXEC_FUN_LOCAL +#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK +#undef DUK_USE_EXEC_TIMEOUT_CHECK +#undef DUK_USE_EXPLICIT_NULL_INIT +#undef DUK_USE_EXTSTR_FREE +#undef DUK_USE_EXTSTR_INTERN_CHECK +#undef DUK_USE_FASTINT +#define DUK_USE_FAST_REFCOUNT_DEFAULT +#define DUK_USE_FILE_IO +#undef DUK_USE_FUNCPTR16 +#undef DUK_USE_FUNCPTR_DEC16 +#undef DUK_USE_FUNCPTR_ENC16 +#undef DUK_USE_GC_TORTURE +#undef DUK_USE_HEAPPTR16 +#undef DUK_USE_HEAPPTR_DEC16 +#undef DUK_USE_HEAPPTR_ENC16 +#define DUK_USE_HEX_FASTPATH +#define DUK_USE_HOBJECT_HASH_PART +#define DUK_USE_HSTRING_CLEN +#undef DUK_USE_HSTRING_EXTDATA +#define DUK_USE_IDCHAR_FASTPATH +#undef DUK_USE_INTERRUPT_COUNTER +#undef DUK_USE_INTERRUPT_DEBUG_FIXUP +#define DUK_USE_JC +#define DUK_USE_JSON_DECNUMBER_FASTPATH +#define DUK_USE_JSON_DECSTRING_FASTPATH +#define DUK_USE_JSON_DEC_RECLIMIT 1000 +#define DUK_USE_JSON_EATWHITE_FASTPATH +#define DUK_USE_JSON_ENC_RECLIMIT 1000 +#define DUK_USE_JSON_QUOTESTRING_FASTPATH +#undef DUK_USE_JSON_STRINGIFY_FASTPATH +#define DUK_USE_JX +#define DUK_USE_LEXER_SLIDING_WINDOW +#undef DUK_USE_LIGHTFUNC_BUILTINS +#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE +#define DUK_USE_MARK_AND_SWEEP +#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 +#define DUK_USE_MATH_BUILTIN +#define DUK_USE_MS_STRINGTABLE_RESIZE +#define DUK_USE_NATIVE_CALL_RECLIMIT 1000 +#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER +#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER +#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT +#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY +#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY +#define DUK_USE_NONSTD_FUNC_STMT +#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT +#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029 +#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE +#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT +#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT +#undef DUK_USE_OBJSIZES16 +#define DUK_USE_OCTAL_SUPPORT +#define DUK_USE_PANIC_ABORT +#undef DUK_USE_PANIC_EXIT +#undef DUK_USE_PANIC_HANDLER +#undef DUK_USE_PANIC_SEGFAULT +#undef DUK_USE_PARANOID_ERRORS +#define DUK_USE_PC2LINE +#undef DUK_USE_PREFER_SIZE +#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS +#undef DUK_USE_REFCOUNT16 +#define DUK_USE_REFERENCE_COUNTING +#undef DUK_USE_REFZERO_FINALIZER_TORTURE +#undef DUK_USE_REGEXP_CANON_WORKAROUND +#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 +#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 +#define DUK_USE_REGEXP_SUPPORT +#undef DUK_USE_ROM_GLOBAL_CLONE +#undef DUK_USE_ROM_GLOBAL_INHERIT +#undef DUK_USE_ROM_OBJECTS +#define DUK_USE_ROM_PTRCOMP_FIRST 63488L +#undef DUK_USE_ROM_STRINGS +#define DUK_USE_SECTION_B +#undef DUK_USE_SELF_TESTS +#undef DUK_USE_SHUFFLE_TORTURE +#define DUK_USE_SOURCE_NONBMP +#undef DUK_USE_STRHASH16 +#undef DUK_USE_STRHASH_DENSE +#define DUK_USE_STRHASH_SKIP_SHIFT 5 +#define DUK_USE_STRICT_DECL +#undef DUK_USE_STRICT_UTF8_SOURCE +#undef DUK_USE_STRLEN16 +#undef DUK_USE_STRTAB_CHAIN +#undef DUK_USE_STRTAB_CHAIN_SIZE +#define DUK_USE_STRTAB_PROBE +#define DUK_USE_TAILCALL +#define DUK_USE_TARGET_INFO "unknown" +#define DUK_USE_TRACEBACKS +#define DUK_USE_TRACEBACK_DEPTH 10 +#define DUK_USE_USER_DECLARE() /* no user declarations */ +#undef DUK_USE_USER_INITJS +#undef DUK_USE_VALSTACK_UNSAFE +#define DUK_USE_VERBOSE_ERRORS +#define DUK_USE_VERBOSE_EXECUTOR_ERRORS +#define DUK_USE_VOLUNTARY_GC +#define DUK_USE_ZERO_BUFFER_DATA + +/* + * Alternative customization header + * + * If you want to modify the final DUK_USE_xxx flags directly (without + * using the available DUK_OPT_xxx flags), define DUK_OPT_HAVE_CUSTOM_H + * and tweak the final flags there. + */ + +#if defined(DUK_OPT_HAVE_CUSTOM_H) +#include "duk_custom.h" +#endif + +/* + * You may add overriding #define/#undef directives below for + * customization. You of course cannot un-#include or un-typedef + * anything; these require direct changes above. + */ + +/* __OVERRIDE_DEFINES__ */ + +/* + * Date provider selection + * + * User may define DUK_USE_DATE_GET_NOW() etc directly, in which case we'll + * rely on an external provider. If this is not done, revert to previous + * behavior and use Unix/Windows built-in provider. + */ + +#if defined(DUK_COMPILING_DUKTAPE) + +#if defined(DUK_USE_DATE_GET_NOW) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday((ctx)) +#elif defined(DUK_USE_DATE_NOW_TIME) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time((ctx)) +#elif defined(DUK_USE_DATE_NOW_WINDOWS) +#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows((ctx)) +#else +#error no provider for DUK_USE_DATE_GET_NOW() +#endif + +#if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) +#elif defined(DUK_USE_DATE_TZO_WINDOWS) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) +#else +#error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() +#endif + +#if defined(DUK_USE_DATE_PARSE_STRING) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_PRS_STRPTIME) +#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_strptime((ctx), (str)) +#elif defined(DUK_USE_DATE_PRS_GETDATE) +#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_getdate((ctx), (str)) +#else +/* No provider for DUK_USE_DATE_PARSE_STRING(), fall back to ISO 8601 only. */ +#endif + +#if defined(DUK_USE_DATE_FORMAT_STRING) +/* External provider already defined. */ +#elif defined(DUK_USE_DATE_FMT_STRFTIME) +#define DUK_USE_DATE_FORMAT_STRING(ctx,parts,tzoffset,flags) \ + duk_bi_date_format_parts_strftime((ctx), (parts), (tzoffset), (flags)) +#else +/* No provider for DUK_USE_DATE_FORMAT_STRING(), fall back to ISO 8601 only. */ +#endif + +#endif /* DUK_COMPILING_DUKTAPE */ + +/* + * Checks for legacy feature options (DUK_OPT_xxx) + */ + +#if defined(DUK_OPT_ASSERTIONS) +#error unsupported legacy feature option DUK_OPT_ASSERTIONS used, consider options: DUK_USE_ASSERTIONS +#endif +#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT) +#error unsupported legacy feature option DUK_OPT_BUFFEROBJECT_SUPPORT used +#endif +#if defined(DUK_OPT_BUFLEN16) +#error unsupported legacy feature option DUK_OPT_BUFLEN16 used +#endif +#if defined(DUK_OPT_DATAPTR16) +#error unsupported legacy feature option DUK_OPT_DATAPTR16 used +#endif +#if defined(DUK_OPT_DATAPTR_DEC16) +#error unsupported legacy feature option DUK_OPT_DATAPTR_DEC16 used +#endif +#if defined(DUK_OPT_DATAPTR_ENC16) +#error unsupported legacy feature option DUK_OPT_DATAPTR_ENC16 used +#endif +#if defined(DUK_OPT_DDDPRINT) +#error unsupported legacy feature option DUK_OPT_DDDPRINT used +#endif +#if defined(DUK_OPT_DDPRINT) +#error unsupported legacy feature option DUK_OPT_DDPRINT used +#endif +#if defined(DUK_OPT_DEBUG) +#error unsupported legacy feature option DUK_OPT_DEBUG used +#endif +#if defined(DUK_OPT_DEBUGGER_DUMPHEAP) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_DUMPHEAP used +#endif +#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_LOGGING used +#endif +#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_PRINTALERT used +#endif +#if defined(DUK_OPT_DEBUGGER_SUPPORT) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_SUPPORT used +#endif +#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE) +#error unsupported legacy feature option DUK_OPT_DEBUGGER_TRANSPORT_TORTURE used +#endif +#if defined(DUK_OPT_DEBUG_BUFSIZE) +#error unsupported legacy feature option DUK_OPT_DEBUG_BUFSIZE used +#endif +#if defined(DUK_OPT_DECLARE) +#error unsupported legacy feature option DUK_OPT_DECLARE used +#endif +#if defined(DUK_OPT_DEEP_C_STACK) +#error unsupported legacy feature option DUK_OPT_DEEP_C_STACK used +#endif +#if defined(DUK_OPT_DLL_BUILD) +#error unsupported legacy feature option DUK_OPT_DLL_BUILD used +#endif +#if defined(DUK_OPT_DPRINT) +#error unsupported legacy feature option DUK_OPT_DPRINT used +#endif +#if defined(DUK_OPT_DPRINT_COLORS) +#error unsupported legacy feature option DUK_OPT_DPRINT_COLORS used +#endif +#if defined(DUK_OPT_DPRINT_RDTSC) +#error unsupported legacy feature option DUK_OPT_DPRINT_RDTSC used +#endif +#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK) +#error unsupported legacy feature option DUK_OPT_EXEC_TIMEOUT_CHECK used +#endif +#if defined(DUK_OPT_EXTERNAL_STRINGS) +#error unsupported legacy feature option DUK_OPT_EXTERNAL_STRINGS used, consider options: DUK_USE_HSTRING_EXTDATA +#endif +#if defined(DUK_OPT_EXTSTR_FREE) +#error unsupported legacy feature option DUK_OPT_EXTSTR_FREE used +#endif +#if defined(DUK_OPT_EXTSTR_INTERN_CHECK) +#error unsupported legacy feature option DUK_OPT_EXTSTR_INTERN_CHECK used +#endif +#if defined(DUK_OPT_FASTINT) +#error unsupported legacy feature option DUK_OPT_FASTINT used, consider options: DUK_USE_FASTINT +#endif +#if defined(DUK_OPT_FORCE_ALIGN) +#error unsupported legacy feature option DUK_OPT_FORCE_ALIGN used +#endif +#if defined(DUK_OPT_FORCE_BYTEORDER) +#error unsupported legacy feature option DUK_OPT_FORCE_BYTEORDER used +#endif +#if defined(DUK_OPT_FUNCPTR16) +#error unsupported legacy feature option DUK_OPT_FUNCPTR16 used +#endif +#if defined(DUK_OPT_FUNCPTR_DEC16) +#error unsupported legacy feature option DUK_OPT_FUNCPTR_DEC16 used +#endif +#if defined(DUK_OPT_FUNCPTR_ENC16) +#error unsupported legacy feature option DUK_OPT_FUNCPTR_ENC16 used +#endif +#if defined(DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY) +#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY used +#endif +#if defined(DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY) +#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY used +#endif +#if defined(DUK_OPT_GC_TORTURE) +#error unsupported legacy feature option DUK_OPT_GC_TORTURE used +#endif +#if defined(DUK_OPT_HAVE_CUSTOM_H) +#error unsupported legacy feature option DUK_OPT_HAVE_CUSTOM_H used +#endif +#if defined(DUK_OPT_HEAPPTR16) +#error unsupported legacy feature option DUK_OPT_HEAPPTR16 used +#endif +#if defined(DUK_OPT_HEAPPTR_DEC16) +#error unsupported legacy feature option DUK_OPT_HEAPPTR_DEC16 used +#endif +#if defined(DUK_OPT_HEAPPTR_ENC16) +#error unsupported legacy feature option DUK_OPT_HEAPPTR_ENC16 used +#endif +#if defined(DUK_OPT_INTERRUPT_COUNTER) +#error unsupported legacy feature option DUK_OPT_INTERRUPT_COUNTER used +#endif +#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH) +#error unsupported legacy feature option DUK_OPT_JSON_STRINGIFY_FASTPATH used +#endif +#if defined(DUK_OPT_LIGHTFUNC_BUILTINS) +#error unsupported legacy feature option DUK_OPT_LIGHTFUNC_BUILTINS used +#endif +#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY used +#endif +#if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY used +#endif +#if defined(DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT) +#error unsupported legacy feature option DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT used +#endif +#if defined(DUK_OPT_NO_AUGMENT_ERRORS) +#error unsupported legacy feature option DUK_OPT_NO_AUGMENT_ERRORS used +#endif +#if defined(DUK_OPT_NO_BROWSER_LIKE) +#error unsupported legacy feature option DUK_OPT_NO_BROWSER_LIKE used +#endif +#if defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_BUFFEROBJECT_SUPPORT used +#endif +#if defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_BYTECODE_DUMP_SUPPORT used, consider options: DUK_USE_BYTECODE_DUMP_SUPPORT +#endif +#if defined(DUK_OPT_NO_COMMONJS_MODULES) +#error unsupported legacy feature option DUK_OPT_NO_COMMONJS_MODULES used +#endif +#if defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY used +#endif +#if defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF) +#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF used +#endif +#if defined(DUK_OPT_NO_ES6_PROXY) +#error unsupported legacy feature option DUK_OPT_NO_ES6_PROXY used +#endif +#if defined(DUK_OPT_NO_FILE_IO) +#error unsupported legacy feature option DUK_OPT_NO_FILE_IO used, consider options: DUK_USE_FILE_IO +#endif +#if defined(DUK_OPT_NO_FUNC_STMT) +#error unsupported legacy feature option DUK_OPT_NO_FUNC_STMT used +#endif +#if defined(DUK_OPT_NO_JC) +#error unsupported legacy feature option DUK_OPT_NO_JC used +#endif +#if defined(DUK_OPT_NO_JSONC) +#error unsupported legacy feature option DUK_OPT_NO_JSONC used +#endif +#if defined(DUK_OPT_NO_JSONX) +#error unsupported legacy feature option DUK_OPT_NO_JSONX used +#endif +#if defined(DUK_OPT_NO_JX) +#error unsupported legacy feature option DUK_OPT_NO_JX used +#endif +#if defined(DUK_OPT_NO_MARK_AND_SWEEP) +#error unsupported legacy feature option DUK_OPT_NO_MARK_AND_SWEEP used +#endif +#if defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE) +#error unsupported legacy feature option DUK_OPT_NO_MS_STRINGTABLE_RESIZE used +#endif +#if defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT used +#endif +#if defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER used +#endif +#if defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER used +#endif +#if defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT used +#endif +#if defined(DUK_OPT_NO_NONSTD_FUNC_STMT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_FUNC_STMT used +#endif +#if defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029 used +#endif +#if defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT) +#error unsupported legacy feature option DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT used +#endif +#if defined(DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY) +#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY used +#endif +#if defined(DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF) +#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF used +#endif +#if defined(DUK_OPT_NO_OCTAL_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_OCTAL_SUPPORT used +#endif +#if defined(DUK_OPT_NO_PACKED_TVAL) +#error unsupported legacy feature option DUK_OPT_NO_PACKED_TVAL used +#endif +#if defined(DUK_OPT_NO_PC2LINE) +#error unsupported legacy feature option DUK_OPT_NO_PC2LINE used +#endif +#if defined(DUK_OPT_NO_REFERENCE_COUNTING) +#error unsupported legacy feature option DUK_OPT_NO_REFERENCE_COUNTING used, consider options: DUK_USE_REFERENCE_COUNTING +#endif +#if defined(DUK_OPT_NO_REGEXP_SUPPORT) +#error unsupported legacy feature option DUK_OPT_NO_REGEXP_SUPPORT used +#endif +#if defined(DUK_OPT_NO_SECTION_B) +#error unsupported legacy feature option DUK_OPT_NO_SECTION_B used +#endif +#if defined(DUK_OPT_NO_SOURCE_NONBMP) +#error unsupported legacy feature option DUK_OPT_NO_SOURCE_NONBMP used +#endif +#if defined(DUK_OPT_NO_STRICT_DECL) +#error unsupported legacy feature option DUK_OPT_NO_STRICT_DECL used +#endif +#if defined(DUK_OPT_NO_TRACEBACKS) +#error unsupported legacy feature option DUK_OPT_NO_TRACEBACKS used +#endif +#if defined(DUK_OPT_NO_VERBOSE_ERRORS) +#error unsupported legacy feature option DUK_OPT_NO_VERBOSE_ERRORS used +#endif +#if defined(DUK_OPT_NO_VOLUNTARY_GC) +#error unsupported legacy feature option DUK_OPT_NO_VOLUNTARY_GC used +#endif +#if defined(DUK_OPT_NO_ZERO_BUFFER_DATA) +#error unsupported legacy feature option DUK_OPT_NO_ZERO_BUFFER_DATA used +#endif +#if defined(DUK_OPT_OBJSIZES16) +#error unsupported legacy feature option DUK_OPT_OBJSIZES16 used +#endif +#if defined(DUK_OPT_PANIC_HANDLER) +#error unsupported legacy feature option DUK_OPT_PANIC_HANDLER used +#endif +#if defined(DUK_OPT_REFCOUNT16) +#error unsupported legacy feature option DUK_OPT_REFCOUNT16 used +#endif +#if defined(DUK_OPT_SEGFAULT_ON_PANIC) +#error unsupported legacy feature option DUK_OPT_SEGFAULT_ON_PANIC used +#endif +#if defined(DUK_OPT_SELF_TESTS) +#error unsupported legacy feature option DUK_OPT_SELF_TESTS used +#endif +#if defined(DUK_OPT_SETJMP) +#error unsupported legacy feature option DUK_OPT_SETJMP used +#endif +#if defined(DUK_OPT_SHUFFLE_TORTURE) +#error unsupported legacy feature option DUK_OPT_SHUFFLE_TORTURE used +#endif +#if defined(DUK_OPT_SIGSETJMP) +#error unsupported legacy feature option DUK_OPT_SIGSETJMP used +#endif +#if defined(DUK_OPT_STRHASH16) +#error unsupported legacy feature option DUK_OPT_STRHASH16 used +#endif +#if defined(DUK_OPT_STRICT_UTF8_SOURCE) +#error unsupported legacy feature option DUK_OPT_STRICT_UTF8_SOURCE used +#endif +#if defined(DUK_OPT_STRLEN16) +#error unsupported legacy feature option DUK_OPT_STRLEN16 used +#endif +#if defined(DUK_OPT_STRTAB_CHAIN) +#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN used +#endif +#if defined(DUK_OPT_STRTAB_CHAIN_SIZE) +#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN_SIZE used +#endif +#if defined(DUK_OPT_TARGET_INFO) +#error unsupported legacy feature option DUK_OPT_TARGET_INFO used +#endif +#if defined(DUK_OPT_TRACEBACK_DEPTH) +#error unsupported legacy feature option DUK_OPT_TRACEBACK_DEPTH used +#endif +#if defined(DUK_OPT_UNDERSCORE_SETJMP) +#error unsupported legacy feature option DUK_OPT_UNDERSCORE_SETJMP used +#endif +#if defined(DUK_OPT_USER_INITJS) +#error unsupported legacy feature option DUK_OPT_USER_INITJS used +#endif + +/* + * Checks for config option consistency (DUK_USE_xxx) + */ + +#if defined(DUK_USE_32BIT_PTRS) +#error unsupported config option used (option has been removed): DUK_USE_32BIT_PTRS +#endif +#if defined(DUK_USE_ALIGN_4) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_4 +#endif +#if defined(DUK_USE_ALIGN_8) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8 +#endif +#if defined(DUK_USE_BYTEORDER_FORCED) +#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED +#endif +#if defined(DUK_USE_DATAPTR_DEC16) && !defined(DUK_USE_DATAPTR16) +#error config option DUK_USE_DATAPTR_DEC16 requires option DUK_USE_DATAPTR16 (which is missing) +#endif +#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16) +#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing) +#endif +#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER) +#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing) +#endif +#if defined(DUK_USE_DEEP_C_STACK) +#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK +#endif +#if defined(DUK_USE_DOUBLE_BE) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_BE +#endif +#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_LE) +#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_LE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_ME) +#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_LE) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_LE +#endif +#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_BE) +#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_BE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_ME) +#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_ME) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_ME +#endif +#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_LE) +#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_LE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_BE) +#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_BE (which is also defined) +#endif +#if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG) +#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing) +#endif +#if defined(DUK_USE_ESBC_MAX_BYTES) && !defined(DUK_USE_ESBC_LIMITS) +#error config option DUK_USE_ESBC_MAX_BYTES requires option DUK_USE_ESBC_LIMITS (which is missing) +#endif +#if defined(DUK_USE_ESBC_MAX_LINENUMBER) && !defined(DUK_USE_ESBC_LIMITS) +#error config option DUK_USE_ESBC_MAX_LINENUMBER requires option DUK_USE_ESBC_LIMITS (which is missing) +#endif +#if defined(DUK_USE_EXEC_TIMEOUT_CHECK) && !defined(DUK_USE_INTERRUPT_COUNTER) +#error config option DUK_USE_EXEC_TIMEOUT_CHECK requires option DUK_USE_INTERRUPT_COUNTER (which is missing) +#endif +#if defined(DUK_USE_EXTSTR_FREE) && !defined(DUK_USE_HSTRING_EXTDATA) +#error config option DUK_USE_EXTSTR_FREE requires option DUK_USE_HSTRING_EXTDATA (which is missing) +#endif +#if defined(DUK_USE_EXTSTR_INTERN_CHECK) && !defined(DUK_USE_HSTRING_EXTDATA) +#error config option DUK_USE_EXTSTR_INTERN_CHECK requires option DUK_USE_HSTRING_EXTDATA (which is missing) +#endif +#if defined(DUK_USE_FULL_TVAL) +#error unsupported config option used (option has been removed): DUK_USE_FULL_TVAL +#endif +#if defined(DUK_USE_FUNCPTR_DEC16) && !defined(DUK_USE_FUNCPTR16) +#error config option DUK_USE_FUNCPTR_DEC16 requires option DUK_USE_FUNCPTR16 (which is missing) +#endif +#if defined(DUK_USE_FUNCPTR_ENC16) && !defined(DUK_USE_FUNCPTR16) +#error config option DUK_USE_FUNCPTR_ENC16 requires option DUK_USE_FUNCPTR16 (which is missing) +#endif +#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS) +#error unsupported config option used (option has been removed): DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS +#endif +#if defined(DUK_USE_HEAPPTR16) && defined(DUK_USE_DEBUG) +#error config option DUK_USE_HEAPPTR16 conflicts with option DUK_USE_DEBUG (which is also defined) +#endif +#if defined(DUK_USE_HEAPPTR_DEC16) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_HEAPPTR_DEC16 requires option DUK_USE_HEAPPTR16 (which is missing) +#endif +#if defined(DUK_USE_HEAPPTR_ENC16) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_HEAPPTR_ENC16 requires option DUK_USE_HEAPPTR16 (which is missing) +#endif +#if defined(DUK_USE_INTEGER_BE) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_BE +#endif +#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_LE) +#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_LE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_ME) +#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_ME (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_LE) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_LE +#endif +#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_BE) +#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_BE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_ME) +#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_ME (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_ME) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_ME +#endif +#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_LE) +#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_LE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE) +#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined) +#endif +#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST) +#error unsupported config option used (option has been removed): DUK_USE_NO_DOUBLE_ALIASING_SELFTEST +#endif +#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) +#error unsupported config option used (option has been removed): DUK_USE_PACKED_TVAL_POSSIBLE +#endif +#if defined(DUK_USE_RDTSC) +#error unsupported config option used (option has been removed): DUK_USE_RDTSC +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && defined(DUK_USE_ROM_GLOBAL_INHERIT) +#error config option DUK_USE_ROM_GLOBAL_CLONE conflicts with option DUK_USE_ROM_GLOBAL_INHERIT (which is also defined) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && defined(DUK_USE_ROM_GLOBAL_CLONE) +#error config option DUK_USE_ROM_GLOBAL_INHERIT conflicts with option DUK_USE_ROM_GLOBAL_CLONE (which is also defined) +#endif +#if defined(DUK_USE_ROM_OBJECTS) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_OBJECTS requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_STRINGS) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_STRINGS requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_SETJMP) +#error unsupported config option used (option has been removed): DUK_USE_SETJMP +#endif +#if defined(DUK_USE_SIGSETJMP) +#error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP +#endif +#if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN) +#error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing) +#endif +#if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) +#error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined) +#endif +#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) +#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE +#endif +#if defined(DUK_USE_UNDERSCORE_SETJMP) +#error unsupported config option used (option has been removed): DUK_USE_UNDERSCORE_SETJMP +#endif + +#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus) +#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler +#endif + +/* + * Convert DUK_USE_BYTEORDER, from whatever source, into currently used + * internal defines. If detection failed, #error out. + */ + +#if defined(DUK_USE_BYTEORDER) +#if (DUK_USE_BYTEORDER == 1) +#define DUK_USE_INTEGER_LE +#define DUK_USE_DOUBLE_LE +#elif (DUK_USE_BYTEORDER == 2) +#define DUK_USE_INTEGER_LE /* integer endianness is little on purpose */ +#define DUK_USE_DOUBLE_ME +#elif (DUK_USE_BYTEORDER == 3) +#define DUK_USE_INTEGER_BE +#define DUK_USE_DOUBLE_BE +#else +#error unsupported: byte order invalid +#endif /* byte order */ +#else +#error unsupported: byte order detection failed +#endif /* defined(DUK_USE_BYTEORDER) */ + +#endif /* DUK_CONFIG_H_INCLUDED */ diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/config/genconfig.py b/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/genconfig.py similarity index 64% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/config/genconfig.py rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/config/genconfig.py index 778705e67..9c996481a 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/config/genconfig.py +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/genconfig.py @@ -1,9 +1,9 @@ -#!/usr/bin/python +#!/usr/bin/env python2 # # Process Duktape option metadata and produce various useful outputs: # -# - duk_config.h matching Duktape 1.x feature option model (DUK_OPT_xxx) -# - duk_config.h for a selected platform, compiler, forced options, etc. +# - duk_config.h with specific or autodetected platform, compiler, and +# architecture; forced options; sanity checks; etc # - option documentation for Duktape 1.x feature options (DUK_OPT_xxx) # - option documentation for Duktape 1.x/2.x config options (DUK_USE_xxx) # @@ -15,9 +15,10 @@ # Instead, the goal is to allow the metadata to be extended, or to provide # a reasonable starting point for manual duk_config.h tweaking. # -# NOTE: For Duktape 1.3 release the main goal is to autogenerate a Duktape -# 1.2 compatible "autodetect" header from snippets. Other outputs are still -# experimental. +# For Duktape 1.3 release the main goal was to autogenerate a Duktape 1.2 +# compatible "autodetect" header from legacy snippets, with other outputs +# being experimental. For Duktape 1.4 duk_config.h is always created from +# modular sources. # import os @@ -30,7 +31,10 @@ import tarfile import tempfile import atexit import shutil -import StringIO +try: + from StringIO import StringIO +except ImportError: + from io import StringIO # # Globals holding scanned metadata, helper snippets, etc @@ -56,6 +60,7 @@ allowed_use_meta_keys = [ 'feature_enables', 'feature_disables', 'feature_snippet', + 'feature_no_default', 'related_feature_defines', 'introduced', 'deprecated', @@ -113,33 +118,28 @@ assumed_provides = { } # Platform files must provide at least these (additional checks -# in validate_platform_file()). +# in validate_platform_file()). Fill-ins provide missing optionals. platform_required_provides = [ - 'DUK_USE_OS_STRING', - 'DUK_SETJMP', 'DUK_LONGJMP', + 'DUK_USE_OS_STRING' # must be #define'd ] # Architecture files must provide at least these (additional checks -# in validate_architecture_file()). +# in validate_architecture_file()). Fill-ins provide missing optionals. architecture_required_provides = [ - 'DUK_USE_ARCH_STRING', - 'DUK_USE_ALIGN_BY', 'DUK_USE_UNALIGNED_ACCESSES_POSSIBLE', 'DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS', - 'DUK_USE_PACKED_TVAL', 'DUK_USE_PACKED_TVAL_POSSIBLE' + 'DUK_USE_ARCH_STRING' ] # Compiler files must provide at least these (additional checks -# in validate_compiler_file()). +# in validate_compiler_file()). Fill-ins provide missing optionals. compiler_required_provides = [ - # XXX: incomplete, maybe a generic fill-in for missing stuff because - # there's quite a lot of required compiler defines. + # Compilers need a lot of defines; missing defines are automatically + # filled in with defaults (which are mostly compiler independent), so + # the requires define list is not very large. - 'DUK_USE_COMPILER_STRING', - - 'DUK_EXTERNAL_DECL', 'DUK_EXTERNAL', - 'DUK_INTERNAL_DECL', 'DUK_INTERNAL', - 'DUK_LOCAL_DECL', 'DUK_LOCAL', - - 'DUK_FILE_MACRO', 'DUK_LINE_MACRO', 'DUK_FUNC_MACRO' + 'DUK_USE_COMPILER_STRING', # must be #define'd + 'DUK_USE_BRANCH_HINTS', # may be #undef'd, as long as provided + 'DUK_USE_VARIADIC_MACROS', # may be #undef'd, as long as provided + 'DUK_USE_UNION_INITIALIZERS' # may be #undef'd, as long as provided ] # @@ -149,7 +149,7 @@ compiler_required_provides = [ def get_auto_delete_tempdir(): tmpdir = tempfile.mkdtemp(suffix='-genconfig') def _f(dirname): - print 'Deleting temporary directory: %r' % dirname + #print('Deleting temporary directory: %r' % dirname) if os.path.isdir(dirname) and '-genconfig' in dirname: shutil.rmtree(dirname) atexit.register(_f, tmpdir) @@ -163,6 +163,7 @@ def strip_comments_from_lines(lines): # Comment contents are stripped of any DUK_ prefixed text to avoid # incorrect requires/provides detection. Other comment text is kept; # in particular a "/* redefine */" comment must remain intact here. + # (The 'redefine' hack is not actively needed now.) # # Avoid Python 2.6 vs. Python 2.7 argument differences. @@ -212,12 +213,9 @@ class Snippet: # matters and this is not handled now.) # # Also, some snippets may #undef/#define another define but - # they don't "provide" the define as such. For example, - # DUK_F_CLANG.h.in undefines DUK_F_GCC defines if clang is - # detected: DUK_F_CLANG.h.in is considered to require - # DUK_F_GCC but doesn't provide it. Such redefinitions are - # marked "/* redefine */" in the snippets. They're best - # avoided, of course. + # they don't "provide" the define as such. Such redefinitions + # are marked "/* redefine */" in the snippets. They're best + # avoided (and not currently needed in Duktape 1.4.0). if autoscan_provides: m = re_line_provides.match(line) @@ -251,7 +249,15 @@ class Snippet: for line in f: if line[-1] == '\n': line = line[:-1] - lines.append(line) + if line[:8] == '#snippet': + m = re.match(r'#snippet\s+"(.*?)"', line) + # XXX: better plumbing for lookup path + sub_fn = os.path.normpath(os.path.join(filename, '..', '..', 'header-snippets', m.group(1))) + #print('#snippet ' + sub_fn) + sn = Snippet.fromFile(sub_fn) + lines += sn.lines + else: + lines.append(line) return Snippet(lines, autoscan_requires=True, autoscan_provides=True) fromFile = classmethod(fromFile) @@ -302,10 +308,12 @@ class FileBuilder: def snippet_relative(self, fn): sn = Snippet.fromFile(os.path.join(self.base_dir, fn)) self.vals.append(sn) + return sn - def snippet_absolute(fn): + def snippet_absolute(self, fn): sn = Snippet.fromFile(fn) self.vals.append(sn) + return sn def cpp_error(self, msg): # XXX: assume no newlines etc @@ -326,6 +334,9 @@ class FileBuilder: else: self.cpp_warning(msg) + def chdr_comment_line(self, msg): + self.vals.append(Snippet([ '/* %s */' % msg ])) + def chdr_block_heading(self, msg): lines = [] lines.append('') @@ -381,7 +392,7 @@ def fill_dependencies_for_snippets(snippets, idx_deps): found = True # at least one other node provides 'k' if not found: - #print 'Resolving %r' % k + #print('Resolving %r' % k) resolved.append(k) # Find a header snippet which provides the missing define. @@ -448,7 +459,8 @@ def fill_dependencies_for_snippets(snippets, idx_deps): # print(repr(graph)) # print(repr(snlist)) - print 'Resolved helper defines: %r' % resolved +# print('Resolved helper defines: %r' % resolved) + print('Resolved %d helper defines' % len(resolved)) def serialize_snippet_list(snippets): ret = [] @@ -563,7 +575,7 @@ def scan_tags_meta(filename): with open(filename, 'rb') as f: tags_meta = yaml.load(f) -def scan_snippets(dirname): +def scan_helper_snippets(dirname): # DUK_F_xxx snippets global helper_snippets helper_snippets = [] @@ -573,33 +585,64 @@ def scan_snippets(dirname): #print('Autoscanning snippet: %s' % fn) helper_snippets.append(Snippet.fromFile(os.path.join(dirname, fn))) +def get_opt_defs(removed=True, deprecated=True, unused=True): + ret = [] + for doc in opt_defs_list: + # XXX: aware of target version + if removed == False and doc.get('removed', None) is not None: + continue + if deprecated == False and doc.get('deprecated', None) is not None: + continue + if unused == False and doc.get('unused', False) == True: + continue + ret.append(doc) + return ret + +def get_use_defs(removed=True, deprecated=True, unused=True): + ret = [] + for doc in use_defs_list: + # XXX: aware of target version + if removed == False and doc.get('removed', None) is not None: + continue + if deprecated == False and doc.get('deprecated', None) is not None: + continue + if unused == False and doc.get('unused', False) == True: + continue + ret.append(doc) + return ret + def validate_platform_file(filename): sn = Snippet.fromFile(filename) - # XXX: move required provides/defines into metadata only for req in platform_required_provides: if req not in sn.provides: raise Exception('Platform %s is missing %s' % (filename, req)) - if not ('DUK_USE_SETJMP' in sn.provides or 'DUK_USE_UNDERSCORE_SETJMP' in sn.provides or - 'DUK_USE_SIGSETJMP' in sn.provides): - raise Exception('Platform %s is missing a setjmp provider' % filename) + # DUK_SETJMP, DUK_LONGJMP, DUK_JMPBUF_TYPE are optional, fill-in + # provides if none defined. def validate_architecture_file(filename): sn = Snippet.fromFile(filename) - # XXX: move required provides/defines into metadata only for req in architecture_required_provides: if req not in sn.provides: raise Exception('Architecture %s is missing %s' % (filename, req)) + # Byte order and alignment defines are allowed to be missing, + # a fill-in will handle them. This is necessary because for + # some architecture byte order and/or alignment may vary between + # targets and may be software configurable. + + # XXX: require automatic detection to be signaled? + # e.g. define DUK_USE_ALIGN_BY -1 + # define DUK_USE_BYTE_ORDER -1 + def validate_compiler_file(filename): sn = Snippet.fromFile(filename) - # XXX: move required provides/defines into metadata only for req in compiler_required_provides: if req not in sn.provides: - raise Exception('Architecture %s is missing %s' % (filename, req)) + raise Exception('Compiler %s is missing %s' % (filename, req)) def get_tag_title(tag): meta = tags_meta.get(tag, None) @@ -739,10 +782,12 @@ def generate_option_documentation(opts, opt_list=None, rst_title=None, include_d return ret.join() def generate_feature_option_documentation(opts): - return generate_option_documentation(opts, opt_list=opt_defs_list, rst_title='Duktape feature options', include_default=False) + defs = get_opt_defs() + return generate_option_documentation(opts, opt_list=defs, rst_title='Duktape feature options', include_default=False) def generate_config_option_documentation(opts): - return generate_option_documentation(opts, opt_list=use_defs_list, rst_title='Duktape config options', include_default=True) + defs = get_use_defs() + return generate_option_documentation(opts, opt_list=defs, rst_title='Duktape config options', include_default=True) # # Helpers for duk_config.h generation @@ -753,15 +798,16 @@ def get_forced_options(opts): # overridden by a more specific one). forced_opts = {} for val in opts.force_options_yaml: - doc = yaml.load(StringIO.StringIO(val)) + doc = yaml.load(StringIO(val)) for k in doc.keys(): if use_defs.has_key(k): pass # key is known else: - print 'WARNING: option override key %s not defined in metadata, ignoring' % k + print('WARNING: option override key %s not defined in metadata, ignoring' % k) forced_opts[k] = doc[k] # shallow copy - print 'Overrides: %s' % json.dumps(forced_opts) + if len(forced_opts.keys()) > 0: + print('Overrides: %s' % json.dumps(forced_opts)) return forced_opts @@ -771,9 +817,10 @@ def emit_default_from_config_meta(ret, doc, forced_opts, undef_done): defname = doc['define'] defval = forced_opts.get(defname, doc['default']) - if defval == True: + # NOTE: careful with Python equality, e.g. "0 == False" is true. + if isinstance(defval, bool) and defval == True: ret.line('#define ' + defname) - elif defval == False: + elif isinstance(defval, bool) and defval == False: if not undef_done: ret.line('#undef ' + defname) else: @@ -802,12 +849,13 @@ def emit_default_from_config_meta(ret, doc, forced_opts, undef_done): # options which will be removed in Duktape 2.x. def add_legacy_feature_option_checks(opts, ret): ret.chdr_block_heading('Checks for legacy feature options (DUK_OPT_xxx)') + ret.empty() defs = [] - for doc in opt_defs_list: + for doc in get_opt_defs(): if doc['define'] not in defs: defs.append(doc['define']) - for doc in use_defs_list: + for doc in get_opt_defs(): for dname in doc.get('related_feature_defines', []): if dname not in defs: defs.append(dname) @@ -815,10 +863,9 @@ def add_legacy_feature_option_checks(opts, ret): for optname in defs: suggested = [] - for doc in use_defs_list: + for doc in get_use_defs(): if optname in doc.get('related_feature_defines', []): suggested.append(doc['define']) - ret.empty() ret.line('#if defined(%s)' % optname) if len(suggested) > 0: ret.cpp_warning_or_error('unsupported legacy feature option %s used, consider options: %s' % (optname, ', '.join(suggested)), opts.sanity_strict) @@ -832,9 +879,10 @@ def add_legacy_feature_option_checks(opts, ret): # options, e.g. inconsistent options, invalid option values. def add_config_option_checks(opts, ret): ret.chdr_block_heading('Checks for config option consistency (DUK_USE_xxx)') + ret.empty() defs = [] - for doc in use_defs_list: + for doc in get_use_defs(): if doc['define'] not in defs: defs.append(doc['define']) defs.sort() @@ -846,29 +894,27 @@ def add_config_option_checks(opts, ret): # XXX: more checks if doc.get('removed', None) is not None: - ret.empty() ret.line('#if defined(%s)' % dname) ret.cpp_warning_or_error('unsupported config option used (option has been removed): %s' % dname, opts.sanity_strict) ret.line('#endif') elif doc.get('deprecated', None) is not None: - ret.empty() ret.line('#if defined(%s)' % dname) ret.cpp_warning_or_error('unsupported config option used (option has been deprecated): %s' % dname, opts.sanity_strict) ret.line('#endif') for req in doc.get('requires', []): - ret.empty() ret.line('#if defined(%s) && !defined(%s)' % (dname, req)) ret.cpp_warning_or_error('config option %s requires option %s (which is missing)' % (dname, req), opts.sanity_strict) ret.line('#endif') for req in doc.get('conflicts', []): - ret.empty() ret.line('#if defined(%s) && defined(%s)' % (dname, req)) ret.cpp_warning_or_error('config option %s conflicts with option %s (which is also defined)' % (dname, req), opts.sanity_strict) ret.line('#endif') ret.empty() + ret.snippet_relative('cpp_exception_sanity.h.in') + ret.empty() # Add a header snippet for providing a __OVERRIDE_DEFINES__ section. def add_override_defines_section(opts, ret): @@ -884,10 +930,10 @@ def add_override_defines_section(opts, ret): # Add automatic DUK_OPT_XXX and DUK_OPT_NO_XXX handling for backwards # compatibility with Duktape 1.2 and before. -def add_feature_option_handling(opts, ret, forced_opts): +def add_feature_option_handling(opts, ret, forced_opts, already_provided_keys): ret.chdr_block_heading('Feature option handling') - for doc in use_defs_list: + for doc in get_use_defs(removed=False, deprecated=False, unused=False): # If a related feature option exists, it can be used to force # enable/disable the target feature. If neither feature option # (DUK_OPT_xxx or DUK_OPT_NO_xxx) is given, revert to default. @@ -919,7 +965,18 @@ def add_feature_option_handling(opts, ret, forced_opts): ret.line('#undef %s' % config_define) ret.line('#else') undef_done = False - emit_default_from_config_meta(ret, doc, forced_opts, undef_done) + + # For some options like DUK_OPT_PACKED_TVAL the default comes + # from platform definition. + if doc.get('feature_no_default', False): + print('Skip default for option %s' % config_define) + ret.line('/* Already provided above */') + elif already_provided_keys.has_key(config_define): + # This is a fallback in case config option metadata is wrong. + print('Skip default for option %s (already provided but not flagged in metadata!)' % config_define) + ret.line('/* Already provided above */') + else: + emit_default_from_config_meta(ret, doc, forced_opts, undef_done) ret.line('#endif') elif doc.has_key('feature_snippet'): ret.lines(doc['feature_snippet']) @@ -939,7 +996,7 @@ def add_duk_active_defines_macro(ret): ret.chdr_block_heading('DUK_ACTIVE_DEFINES macro (development only)') idx = 0 - for doc in use_defs_list: + for doc in get_use_defs(): defname = doc['define'] ret.line('#if defined(%s)' % defname) @@ -960,250 +1017,21 @@ def add_duk_active_defines_macro(ret): # duk_config.h generation # -# Generate the default duk_config.h which provides automatic detection of -# platform, compiler, architecture, and features for major platforms. -# Use manually written monolithic header snippets from Duktape 1.2 for -# generating the header. This header is Duktape 1.2 compatible and supports -# DUK_OPT_xxx feature options. Later on the DUK_OPT_xxx options will be -# removed and users can override DUK_USE_xxx flags directly by modifying -# duk_config.h or by generating a new header using genconfig. -def generate_autodetect_duk_config_header(opts, meta_dir): - ret = FileBuilder(base_dir=os.path.join(meta_dir, 'header-snippets'), \ - use_cpp_warning=opts.use_cpp_warning) - - forced_opts = get_forced_options(opts) - - ret.snippet_relative('comment_prologue.h.in') - ret.empty() - - ret.line('#ifndef DUK_CONFIG_H_INCLUDED') - ret.line('#define DUK_CONFIG_H_INCLUDED') - ret.empty() - - # Compiler features, processor/architecture, OS, compiler - ret.snippet_relative('compiler_features.h.in') - ret.empty() - ret.snippet_relative('rdtsc.h.in') # XXX: move downwards - ret.empty() - ret.snippet_relative('platform1.h.in') - ret.empty() - - # Feature selection, system include, Date provider - # Most #include statements are here - ret.snippet_relative('platform2.h.in') - ret.empty() - ret.snippet_relative('ullconsts.h.in') - ret.empty() - ret.snippet_relative('libc.h.in') - ret.empty() - - # Number types - ret.snippet_relative('types1.h.in') - ret.line('#if defined(DUK_F_HAVE_INTTYPES)') - ret.line('/* C99 or compatible */') - ret.empty() - ret.snippet_relative('types_c99.h.in') - ret.empty() - ret.line('#else /* C99 types */') - ret.empty() - ret.snippet_relative('types_legacy.h.in') - ret.empty() - ret.line('#endif /* C99 types */') - ret.empty() - ret.snippet_relative('types2.h.in') - ret.empty() - ret.snippet_relative('64bitops.h.in') - ret.empty() - - # Alignment - ret.snippet_relative('alignment.h.in') - ret.empty() - - # Object layout - ret.snippet_relative('object_layout.h.in') - ret.empty() - - # Byte order - ret.snippet_relative('byteorder.h.in') - ret.empty() - - # Packed duk_tval - ret.snippet_relative('packed_tval.h.in') - ret.empty() - - # Detect 'fast math' - ret.snippet_relative('reject_fast_math.h.in') - ret.empty() - - # IEEE double constants - ret.snippet_relative('double_const.h.in') - ret.empty() - - # Math and other ANSI replacements, NetBSD workaround, paranoid math, paranoid Date - ret.snippet_relative('repl_math.h.in') - ret.empty() - ret.snippet_relative('paranoid_date.h.in') - ret.empty() - ret.snippet_relative('repl_ansi.h.in') - ret.empty() - - # Platform function pointers - ret.snippet_relative('platform_funcptr.h.in') - ret.empty() - - # General compiler stuff - ret.snippet_relative('stringify.h.in') - ret.empty() - ret.snippet_relative('segfault.h.in') - ret.empty() - ret.snippet_relative('unreferenced.h.in') - ret.empty() - ret.snippet_relative('noreturn.h.in') - ret.empty() - ret.snippet_relative('unreachable.h.in') - ret.empty() - ret.snippet_relative('likely.h.in') - ret.empty() - ret.snippet_relative('inline.h.in') - ret.empty() - ret.snippet_relative('visibility.h.in') - ret.empty() - ret.snippet_relative('file_line_func.h.in') - ret.empty() - ret.snippet_relative('byteswap.h.in') - ret.empty() - - # Arhitecture, OS, and compiler strings - ret.snippet_relative('arch_string.h.in') - ret.empty() - ret.snippet_relative('os_string.h.in') - ret.empty() - ret.snippet_relative('compiler_string.h.in') - ret.empty() - - # Target info - ret.snippet_relative('target_info.h.in') - ret.empty() - - # Longjmp handling - ret.snippet_relative('longjmp.h.in') - ret.empty() - - # Unsorted flags, contains almost all actual Duktape-specific - # but platform independent features - ret.snippet_relative('unsorted_flags.h.in') - ret.empty() - - # User declarations - ret.snippet_relative('user_declare.h.in') - ret.empty() - - # Emit forced options. If a corresponding option is already defined - # by a snippet above, #undef it first. - - tmp = Snippet(ret.join().split('\n')) - first_forced = True - for doc in use_defs_list: - defname = doc['define'] - - if doc.get('removed', None) is not None and opts.omit_removed_config_options: - continue - if doc.get('deprecated', None) is not None and opts.omit_deprecated_config_options: - continue - if doc.get('unused', False) == True and opts.omit_unused_config_options: - continue - if not forced_opts.has_key(defname): - continue - - if not doc.has_key('default'): - raise Exception('config option %s is missing default value' % defname) - - if first_forced: - ret.chdr_block_heading('Forced options') - first_forced = False - - undef_done = False - if tmp.provides.has_key(defname): - ret.line('#undef ' + defname) - undef_done = True - - emit_default_from_config_meta(ret, doc, forced_opts, undef_done) - - ret.empty() - - # If manually-edited snippets don't #define or #undef a certain - # config option, emit a default value here. This is useful to - # fill-in for new config options not covered by manual snippets - # (which is intentional). - - tmp = Snippet(ret.join().split('\n')) - need = {} - for doc in use_defs_list: - if doc.get('removed', None) is not None: # XXX: check version - continue - need[doc['define']] = True - for k in tmp.provides.keys(): - if need.has_key(k): - del need[k] - need_keys = sorted(need.keys()) - - if len(need_keys) > 0: - ret.chdr_block_heading('Autogenerated defaults') - - for k in need_keys: - #print('config option %s not covered by manual snippets, emitting default automatically' % k) - emit_default_from_config_meta(ret, use_defs[k], {}, False) - - ret.empty() - - ret.snippet_relative('custom_header.h.in') - ret.empty() - - if len(opts.fixup_header_lines) > 0: - ret.chdr_block_heading('Fixups') - for line in opts.fixup_header_lines: - ret.line(line) - ret.empty() - - add_override_defines_section(opts, ret) - - # Date provider snippet is after custom header and overrides, so that - # the user may define e.g. DUK_USE_DATE_NOW_GETTIMEOFDAY in their - # custom header. - ret.snippet_relative('date_provider.h.in') - ret.empty() - - # Sanity checks - # XXX: use autogenerated sanity checks instead - ret.snippet_relative('sanity.h.in') - ret.empty() - - if opts.emit_legacy_feature_check: - # XXX: this doesn't really make sense for the autodetect - # header yet, because sanity.h.in already covers these. - add_legacy_feature_option_checks(opts, ret) - if opts.emit_config_sanity_check: - add_config_option_checks(opts, ret) - if opts.add_active_defines_macro: - add_duk_active_defines_macro(ret) - - ret.line('#endif /* DUK_CONFIG_H_INCLUDED */') - ret.empty() # for trailing newline - return remove_duplicate_newlines(ret.join()) - # Generate a duk_config.h where platform, architecture, and compiler are -# all either autodetected or specified by user. When autodetection is -# used, the generated header is based on modular snippets and metadata to -# be more easily maintainable than manually edited monolithic snippets. +# all either autodetected or specified by user. # -# This approach will replace the legacy autodetect header in Duktape 1.4, -# and most likely the separate barebones header also. +# Autodetection is based on a configured list of supported platforms, +# architectures, and compilers. For example, platforms.yaml defines the +# supported platforms and provides a helper define (DUK_F_xxx) to use for +# detecting that platform, and names the header snippet to provide the +# platform-specific definitions. Necessary dependencies (DUK_F_xxx) are +# automatically pulled in. # -# The generated header is Duktape 1.2 compatible for now, and supports -# DUK_OPT_xxx feature options. Later on the DUK_OPT_xxx options will be -# removed and user code overrides DUK_USE_xxx flags directly by modifying -# duk_config.h manually or by generating a new header using genconfig. -def generate_autodetect_duk_config_header_modular(opts, meta_dir): +# Automatic "fill ins" are used for mandatory platform, architecture, and +# compiler defines which have a reasonable portable default. This reduces +# e.g. compiler-specific define count because there are a lot compiler +# macros which have a good default. +def generate_duk_config_header(opts, meta_dir): ret = FileBuilder(base_dir=os.path.join(meta_dir, 'header-snippets'), \ use_cpp_warning=opts.use_cpp_warning) @@ -1219,11 +1047,15 @@ def generate_autodetect_duk_config_header_modular(opts, meta_dir): with open(os.path.join(meta_dir, 'compilers.yaml'), 'rb') as f: compilers = yaml.load(f) + # XXX: indicate feature option support, sanity checks enabled, etc + # in general summary of options, perhaps genconfig command line? + ret.line('/*') - ret.line(' * duk_config.h autodetect header generated by genconfig.py.') + ret.line(' * duk_config.h configuration header generated by genconfig.py.') ret.line(' *') ret.line(' * Git commit: %s' % opts.git_commit or 'n/a') ret.line(' * Git describe: %s' % opts.git_describe or 'n/a') + ret.line(' * Git branch: %s' % opts.git_branch or 'n/a') ret.line(' *') if opts.platform is not None: ret.line(' * Platform: ' + opts.platform) @@ -1248,13 +1080,35 @@ def generate_autodetect_duk_config_header_modular(opts, meta_dir): ret.line(' *') ret.line(' */') ret.empty() - ret.line('#ifndef DUK_CONFIG_H_INCLUDED') + ret.line('#if !defined(DUK_CONFIG_H_INCLUDED)') ret.line('#define DUK_CONFIG_H_INCLUDED') ret.empty() ret.chdr_block_heading('Intermediate helper defines') - idx_deps = len(ret.vals) # position where to emit dependencies + # DLL build affects visibility attributes on Windows but unfortunately + # cannot be detected automatically from preprocessor defines or such. + # DLL build status is hidden behind DUK_F_DLL_BUILD and there are two + # ways for that to be set: + # + # - Duktape 1.3 backwards compatible DUK_OPT_DLL_BUILD + # - Genconfig --dll option + ret.chdr_comment_line('DLL build detection') + ret.line('#if defined(DUK_OPT_DLL_BUILD)') + ret.line('#define DUK_F_DLL_BUILD') + ret.line('#elif defined(DUK_OPT_NO_DLL_BUILD)') + ret.line('#undef DUK_F_DLL_BUILD') + ret.line('#else') + if opts.dll: + ret.line('/* configured for DLL build */') + ret.line('#define DUK_F_DLL_BUILD') + else: + ret.line('/* not configured for DLL build */') + ret.line('#undef DUK_F_DLL_BUILD') + ret.line('#endif') + ret.empty() + + idx_deps = len(ret.vals) # position where to emit DUK_F_xxx dependencies # Feature selection, system include, Date provider # Most #include statements are here @@ -1267,8 +1121,9 @@ def generate_autodetect_duk_config_header_modular(opts, meta_dir): # XXX: better to lookup platforms metadata include = 'platform_%s.h.in' % opts.platform - validate_platform_file(os.path.join(meta_dir, 'header-snippets', include)) - ret.snippet_relative(include) + abs_fn = os.path.join(meta_dir, 'platforms', include) + validate_platform_file(abs_fn) + ret.snippet_absolute(abs_fn) else: ret.chdr_block_heading('Platform autodetection') @@ -1278,7 +1133,9 @@ def generate_autodetect_duk_config_header_modular(opts, meta_dir): for idx, platf in enumerate(platforms['autodetect']): check = platf.get('check', None) include = platf['include'] - validate_platform_file(os.path.join(meta_dir, 'header-snippets', include)) + abs_fn = os.path.join(meta_dir, 'platforms', include) + + validate_platform_file(abs_fn) if idx == 0: ret.line('#if defined(%s)' % check) @@ -1287,26 +1144,43 @@ def generate_autodetect_duk_config_header_modular(opts, meta_dir): ret.line('#else') else: ret.line('#elif defined(%s)' % check) - ret.snippet_relative(include) + ret.line('/* --- %s --- */' % platf.get('name', '???')) + ret.snippet_absolute(abs_fn) ret.line('#endif /* autodetect platform */') + ret.empty() ret.snippet_relative('platform_sharedincludes.h.in') ret.empty() + byteorder_provided_by_all = True # byteorder provided by all architecture files + alignment_provided_by_all = True # alignment provided by all architecture files + packedtval_provided_by_all = True # packed tval provided by all architecture files + if opts.architecture is not None: ret.chdr_block_heading('Architecture: ' + opts.architecture) # XXX: better to lookup architectures metadata include = 'architecture_%s.h.in' % opts.architecture - validate_architecture_file(os.path.join(meta_dir, 'header-snippets', include)) - ret.snippet_relative(include) + abs_fn = os.path.join(meta_dir, 'architectures', include) + validate_architecture_file(abs_fn) + sn = ret.snippet_absolute(abs_fn) + if not sn.provides.get('DUK_USE_BYTEORDER', False): + byteorder_provided_by_all = False + if not sn.provides.get('DUK_USE_ALIGN_BY', False): + alignment_provided_by_all = False + if sn.provides.get('DUK_USE_PACKED_TVAL', False): + ret.line('#define DUK_F_PACKED_TVAL_PROVIDED') # signal to fillin + else: + packedtval_provided_by_all = False else: ret.chdr_block_heading('Architecture autodetection') for idx, arch in enumerate(architectures['autodetect']): check = arch.get('check', None) include = arch['include'] - validate_architecture_file(os.path.join(meta_dir, 'header-snippets', include)) + abs_fn = os.path.join(meta_dir, 'architectures', include) + + validate_architecture_file(abs_fn) if idx == 0: ret.line('#if defined(%s)' % check) @@ -1315,23 +1189,37 @@ def generate_autodetect_duk_config_header_modular(opts, meta_dir): ret.line('#else') else: ret.line('#elif defined(%s)' % check) - ret.snippet_relative(include) + ret.line('/* --- %s --- */' % arch.get('name', '???')) + sn = ret.snippet_absolute(abs_fn) + if not sn.provides.get('DUK_USE_BYTEORDER', False): + byteorder_provided_by_all = False + if not sn.provides.get('DUK_USE_ALIGN_BY', False): + alignment_provided_by_all = False + if sn.provides.get('DUK_USE_PACKED_TVAL', False): + ret.line('#define DUK_F_PACKED_TVAL_PROVIDED') # signal to fillin + else: + packedtval_provided_by_all = False ret.line('#endif /* autodetect architecture */') + ret.empty() + if opts.compiler is not None: ret.chdr_block_heading('Compiler: ' + opts.compiler) # XXX: better to lookup compilers metadata include = 'compiler_%s.h.in' % opts.compiler - validate_compiler_file(os.path.join(meta_dir, 'header-snippets', include)) - ret.snippet_relative(include) + abs_fn = os.path.join(meta_dir, 'compilers', include) + validate_compiler_file(abs_fn) + sn = ret.snippet_absolute(abs_fn) else: ret.chdr_block_heading('Compiler autodetection') for idx, comp in enumerate(compilers['autodetect']): check = comp.get('check', None) include = comp['include'] - validate_compiler_file(os.path.join(meta_dir, 'header-snippets', include)) + abs_fn = os.path.join(meta_dir, 'compilers', include) + + validate_compiler_file(abs_fn) if idx == 0: ret.line('#if defined(%s)' % check) @@ -1340,143 +1228,95 @@ def generate_autodetect_duk_config_header_modular(opts, meta_dir): ret.line('#else') else: ret.line('#elif defined(%s)' % check) - ret.snippet_relative(include) + ret.line('/* --- %s --- */' % comp.get('name', '???')) + sn = ret.snippet_absolute(abs_fn) ret.line('#endif /* autodetect compiler */') - # FIXME: The snippets below have some conflicts with the platform, - # architecture, and compiler snippets files included above. These - # need to be resolved so that (a) each define is only provided from - # one place or (b) the latter definition is a "fill-in" which is - # only used when a certain define is missing from e.g. a compiler - # snippet (useful for e.g. compiler defines which have sane, standard - # defaults). - - # FIXME: __uclibc__ needs stdlib.h, but it really is the only exception - ret.snippet_relative('libc.h.in') ret.empty() + # DUK_F_UCLIBC is special because __UCLIBC__ is provided by an #include + # file, so the check must happen after platform includes. It'd be nice + # for this to be automatic (e.g. DUK_F_UCLIBC.h.in could indicate the + # dependency somehow). + + ret.snippet_absolute(os.path.join(meta_dir, 'helper-snippets', 'DUK_F_UCLIBC.h.in')) + ret.empty() + + # XXX: platform/compiler could provide types; if so, need some signaling + # defines like DUK_F_TYPEDEFS_DEFINED + # Number types - ret.snippet_relative('types1.h.in') - ret.line('#if defined(DUK_F_HAVE_INTTYPES)') - ret.line('/* C99 or compatible */') - ret.empty() - ret.snippet_relative('types_c99.h.in') - ret.empty() - ret.line('#else /* C99 types */') - ret.empty() - ret.snippet_relative('types_legacy.h.in') - ret.empty() - ret.line('#endif /* C99 types */') - ret.empty() + if opts.c99_types_only: + ret.snippet_relative('types1.h.in') + ret.line('/* C99 types assumed */') + ret.snippet_relative('types_c99.h.in') + ret.empty() + else: + ret.snippet_relative('types1.h.in') + ret.line('#if defined(DUK_F_HAVE_INTTYPES)') + ret.line('/* C99 or compatible */') + ret.empty() + ret.snippet_relative('types_c99.h.in') + ret.empty() + ret.line('#else /* C99 types */') + ret.empty() + ret.snippet_relative('types_legacy.h.in') + ret.empty() + ret.line('#endif /* C99 types */') + ret.empty() ret.snippet_relative('types2.h.in') ret.empty() ret.snippet_relative('64bitops.h.in') ret.empty() - # Alignment - ret.snippet_relative('alignment.h.in') + # Platform, architecture, compiler fillins. These are after all + # detection so that e.g. DUK_SPRINTF() can be provided by platform + # or compiler before trying a fill-in. + + ret.chdr_block_heading('Fill-ins for platform, architecture, and compiler') + + ret.snippet_relative('platform_fillins.h.in') ret.empty() + ret.snippet_relative('architecture_fillins.h.in') + if not byteorder_provided_by_all: + ret.empty() + ret.snippet_relative('byteorder_fillin.h.in') + if not alignment_provided_by_all: + ret.empty() + ret.snippet_relative('alignment_fillin.h.in') + ret.empty() + ret.snippet_relative('compiler_fillins.h.in') + ret.empty() + ret.snippet_relative('inline_workaround.h.in') + ret.empty() + if not packedtval_provided_by_all: + ret.empty() + ret.snippet_relative('packed_tval_fillin.h.in') # Object layout ret.snippet_relative('object_layout.h.in') ret.empty() - # Byte order - # FIXME: from the architecture snippet - ret.snippet_relative('byteorder.h.in') - ret.empty() - - # Packed duk_tval - # FIXME: from the architecture snippet - ret.snippet_relative('packed_tval.h.in') - ret.empty() - - # Detect 'fast math' + # Detect and reject 'fast math' ret.snippet_relative('reject_fast_math.h.in') ret.empty() - # IEEE double constants - # FIXME: these should maybe be 'fill-ins' if previous headers - # didn't provide something - ret.snippet_relative('double_const.h.in') - ret.empty() - - # Math and other ANSI replacements, NetBSD workaround, paranoid math, paranoid Date - ret.snippet_relative('repl_math.h.in') - ret.empty() - ret.snippet_relative('paranoid_date.h.in') - ret.empty() - ret.snippet_relative('repl_ansi.h.in') - ret.empty() - - # Platform function pointers - ret.snippet_relative('platform_funcptr.h.in') - ret.empty() - - # General compiler stuff - ret.snippet_relative('stringify.h.in') - ret.empty() - ret.snippet_relative('segfault.h.in') - ret.empty() - ret.snippet_relative('unreferenced.h.in') - ret.empty() - ret.snippet_relative('noreturn.h.in') - ret.empty() - ret.snippet_relative('unreachable.h.in') - ret.empty() - ret.snippet_relative('likely.h.in') - ret.empty() - ret.snippet_relative('inline.h.in') - ret.empty() - ret.snippet_relative('visibility.h.in') - ret.empty() - ret.snippet_relative('file_line_func.h.in') - ret.empty() - ret.snippet_relative('byteswap.h.in') - ret.empty() - - # These come directly from platform, architecture, and compiler - # snippets. - #ret.snippet_relative('arch_string.h.in') - #ret.empty() - #ret.snippet_relative('os_string.h.in') - #ret.empty() - #ret.snippet_relative('compiler_string.h.in') - #ret.empty() - #ret.snippet_relative('longjmp.h.in') - #ret.empty() - - # Target info - ret.snippet_relative('target_info.h.in') - ret.empty() - # Automatic DUK_OPT_xxx feature option handling - # FIXME: platform setjmp/longjmp defines now conflict with this - if True: - # Unsorted flags, contains almost all actual Duktape-specific - # but platform independent features - #ret.snippet_relative('unsorted_flags.h.in') - #ret.empty() - - add_feature_option_handling(opts, ret, forced_opts) - - ret.snippet_relative('user_declare.h.in') - ret.empty() + if opts.support_feature_options: + print('Autogenerating feature option (DUK_OPT_xxx) support') + tmp = Snippet(ret.join().split('\n')) + add_feature_option_handling(opts, ret, forced_opts, tmp.provides) # Emit forced options. If a corresponding option is already defined # by a snippet above, #undef it first. tmp = Snippet(ret.join().split('\n')) first_forced = True - for doc in use_defs_list: + for doc in get_use_defs(removed=not opts.omit_removed_config_options, + deprecated=not opts.omit_deprecated_config_options, + unused=not opts.omit_unused_config_options): defname = doc['define'] - if doc.get('removed', None) is not None and opts.omit_removed_config_options: - continue - if doc.get('deprecated', None) is not None and opts.omit_deprecated_config_options: - continue - if doc.get('unused', False) == True and opts.omit_unused_config_options: - continue if not forced_opts.has_key(defname): continue @@ -1503,9 +1343,7 @@ def generate_autodetect_duk_config_header_modular(opts, meta_dir): tmp = Snippet(ret.join().split('\n')) need = {} - for doc in use_defs_list: - if doc.get('removed', None) is not None: # XXX: check version - continue + for doc in get_use_defs(removed=False): need[doc['define']] = True for k in tmp.provides.keys(): if need.has_key(k): @@ -1540,189 +1378,23 @@ def generate_autodetect_duk_config_header_modular(opts, meta_dir): ret.fill_dependencies_for_snippets(idx_deps) - # FIXME: use autogenerated sanity instead of sanity.h.in - - ret.snippet_relative('sanity.h.in') - ret.empty() - if opts.emit_legacy_feature_check: - # FIXME: this doesn't really make sense for the autodetect header yet add_legacy_feature_option_checks(opts, ret) if opts.emit_config_sanity_check: add_config_option_checks(opts, ret) if opts.add_active_defines_macro: add_duk_active_defines_macro(ret) + # Derived defines (DUK_USE_INTEGER_LE, etc) from DUK_USE_BYTEORDER. + # Duktape internals currently rely on the derived defines. This is + # after sanity checks because the derived defines are marked removed. + ret.snippet_relative('byteorder_derived.h.in') + ret.empty() + ret.line('#endif /* DUK_CONFIG_H_INCLUDED */') ret.empty() # for trailing newline return remove_duplicate_newlines(ret.join()) -# Generate a barebones duk_config.h header for a specific platform, architecture, -# and compiler. The header won't do automatic feature detection and does not -# support DUK_OPT_xxx feature options (which will be removed in Duktape 2.x). -# Users can then modify this barebones header for very exotic platforms and manage -# the needed changes either as a YAML file or by appending a fixup header snippet. -# -# XXX: to be replaced by generate_modular_duk_config_header(). -def generate_barebones_duk_config_header(opts, meta_dir): - ret = FileBuilder(base_dir=os.path.join(meta_dir, 'header-snippets'), \ - use_cpp_warning=opts.use_cpp_warning) - - # XXX: Provide more defines from YAML config files so that such - # defines can be overridden more conveniently (e.g. DUK_COS). - - forced_opts = get_forced_options(opts) - - ret.line('/*') - ret.line(' * duk_config.h generated by genconfig.py for:') - ret.line(' * platform: %s' % opts.platform) - ret.line(' * compiler: %s' % opts.compiler) - ret.line(' * architecture: %s' % opts.architecture) - ret.line(' *') - ret.line(' * Git commit: %s' % opts.git_commit or 'n/a') - ret.line(' * Git describe: %s' % opts.git_describe or 'n/a') - ret.line(' */') - ret.empty() - ret.line('#ifndef DUK_CONFIG_H_INCLUDED') - ret.line('#define DUK_CONFIG_H_INCLUDED') - - ret.chdr_block_heading('Intermediate helper defines') - - idx_deps = len(ret.vals) # position where to emit dependencies - - ret.chdr_block_heading('Platform headers and typedefs') - - if opts.platform is None: - raise Exception('no platform specified') - - fn = 'platform_%s.h.in' % opts.platform - ret.snippet_relative(fn) - ret.empty() - ret.snippet_relative('types_c99.h.in') # XXX: C99 typedefs forced for now - ret.snippet_relative('types2.h.in') # XXX: boilerplate type stuff - - ret.chdr_block_heading('Platform features') - - # XXX: double constants - # XXX: replacement functions - # XXX: inherit definitions (like '#define DUK_FFLUSH fflush') from a - # generic set of defaults, allow platform configs to override - - ret.snippet_relative('platform_generic.h.in') - - ret.chdr_block_heading('Compiler features') - - if opts.compiler is None: - raise Exception('no compiler specified') - - fn = 'compiler_%s.h.in' % opts.compiler - ret.snippet_relative(fn) - - # noreturn, vacopy, etc - # visibility attributes - - ret.chdr_block_heading('Architecture features') - - if opts.architecture is None: - raise Exception('no architecture specified') - - fn = 'architecture_%s.h.in' % opts.architecture - ret.snippet_relative(fn) - - ret.chdr_block_heading('Config options') - - tags = get_tag_list_with_preferred_order(header_tag_order) - - handled = {} - - # Mark all defines 'provided' by the snippets so far as handled. - # For example, if the system header provides a DUK_USE_OS_STRING, - # we won't emit it again below with its default value (but will - # emit an override value if specified). - - for sn in ret.vals: - for k in sn.provides.keys(): - handled[k] = True - - for tag in tags: - ret.line('/* ' + get_tag_title(tag) + ' */') - - for doc in use_defs_list: - defname = doc['define'] - - if doc.get('removed', None) is not None and opts.omit_removed_config_options: - continue - if doc.get('deprecated', None) is not None and opts.omit_deprecated_config_options: - continue - if doc.get('unused', False) == True and opts.omit_unused_config_options: - continue - - if tag != doc['tags'][0]: # sort under primary tag - continue - - if not doc.has_key('default'): - raise Exception('config option %s is missing default value' % defname) - - undef_done = False - - if handled.has_key(defname): - defval = forced_opts.get(defname, None) - if defval is None: - ret.line('/* %s already emitted above */' % defname) - continue - - # Define already emitted by snippets above but - # an explicit override wants to redefine it. - # Undef first and then use shared handler to - # setup the forced value. - ret.line('#undef ' + defname) - undef_done = True - - # FIXME: macro args; DUK_USE_USER_DECLARE vs. DUK_USE_USER_DECLARE() - # vs. DUK_USE_USER_DECLARE(x,y) - - handled[defname] = True - emit_default_from_config_meta(ret, doc, forced_opts, undef_done) - - ret.empty() - - if len(opts.fixup_header_lines) > 0: - ret.chdr_block_heading('Fixups') - for line in opts.fixup_header_lines: - ret.line(line) - - add_override_defines_section(opts, ret) - - # Date provider snippet is after custom header and overrides, so that - # the user may define e.g. DUK_USE_DATE_NOW_GETTIMEOFDAY in their - # custom header. - ret.empty() - ret.snippet_relative('date_provider.h.in') - ret.empty() - - ret.fill_dependencies_for_snippets(idx_deps) - - # XXX: ensure no define is unhandled at the end - - # Check for presence of legacy feature options (DUK_OPT_xxx), - # and consistency of final DUK_USE_xxx options. - # - # These could also be emitted into Duktape source code, but it's - # probably better that the checks can be easily disabled from - # duk_config.h. - - if opts.emit_legacy_feature_check: - add_legacy_feature_option_checks(opts, ret) - if opts.emit_config_sanity_check: - add_config_option_checks(opts, ret) - if opts.add_active_defines_macro: - add_duk_active_defines_macro(ret) - - ret.line('#endif /* DUK_CONFIG_H_INCLUDED */') - ret.empty() # for trailing newline - - return remove_duplicate_newlines(serialize_snippet_list(ret.vals)) # XXX: refactor into FileBuilder - # # Main # @@ -1766,8 +1438,7 @@ def main(): fixup_header_lines.append(line) commands = [ - 'autodetect-header', - 'barebones-header', + 'duk-config-header', 'feature-documentation', 'config-documentation' ] @@ -1776,12 +1447,15 @@ def main(): description='Generate a duk_config.h or config option documentation based on config metadata.', epilog='COMMAND can be one of: ' + ', '.join(commands) + '.' ) + parser.add_option('--metadata', dest='metadata', default=None, help='metadata directory or metadata tar.gz file') parser.add_option('--output', dest='output', default=None, help='output filename for C header or RST documentation file') parser.add_option('--platform', dest='platform', default=None, help='platform (for "barebones-header" command)') parser.add_option('--compiler', dest='compiler', default=None, help='compiler (for "barebones-header" command)') parser.add_option('--architecture', dest='architecture', default=None, help='architecture (for "barebones-header" command)') - parser.add_option('--dll', dest='dll', action='store_true', default=False, help='dll build of Duktape, affects symbol visibility macros especially on Windows') # FIXME: unimplemented + parser.add_option('--c99-types-only', dest='c99_types_only', action='store_true', default=False, help='assume C99 types, no legacy type detection') + parser.add_option('--dll', dest='dll', action='store_true', default=False, help='dll build of Duktape, affects symbol visibility macros especially on Windows') + parser.add_option('--support-feature-options', dest='support_feature_options', action='store_true', default=False, help='support DUK_OPT_xxx feature options in duk_config.h') parser.add_option('--emit-legacy-feature-check', dest='emit_legacy_feature_check', action='store_true', default=False, help='emit preprocessor checks to reject legacy feature options (DUK_OPT_xxx)') parser.add_option('--emit-config-sanity-check', dest='emit_config_sanity_check', action='store_true', default=False, help='emit preprocessor checks for config option consistency (DUK_OPT_xxx)') parser.add_option('--omit-removed-config-options', dest='omit_removed_config_options', action='store_true', default=False, help='omit removed config options from generated headers') @@ -1800,6 +1474,7 @@ def main(): parser.add_option('--use-cpp-warning', dest='use_cpp_warning', action='store_true', default=False, help='emit a (non-portable) #warning when appropriate') parser.add_option('--git-commit', dest='git_commit', default=None, help='git commit hash to be included in header comments') parser.add_option('--git-describe', dest='git_describe', default=None, help='git describe string to be included in header comments') + parser.add_option('--git-branch', dest='git_branch', default=None, help='git branch string to be included in header comments') (opts, args) = parser.parse_args() meta_dir = opts.metadata @@ -1811,50 +1486,40 @@ def main(): if opts.metadata is not None and os.path.isdir(opts.metadata): meta_dir = opts.metadata - print 'Using metadata directory: %r' % meta_dir + metadata_src_text = 'Using metadata directory: %r' % meta_dir elif opts.metadata is not None and os.path.isfile(opts.metadata) and tarfile.is_tarfile(opts.metadata): meta_dir = get_auto_delete_tempdir() tar = tarfile.open(name=opts.metadata, mode='r:*') tar.extractall(path=meta_dir) - print 'Using metadata tar file %r, unpacked to directory: %r' % (opts.metadata, meta_dir) + metadata_src_text = 'Using metadata tar file %r, unpacked to directory: %r' % (opts.metadata, meta_dir) else: raise Exception('metadata source must be a directory or a tar.gz file') - scan_snippets(os.path.join(meta_dir, 'header-snippets')) + scan_helper_snippets(os.path.join(meta_dir, 'helper-snippets')) scan_use_defs(os.path.join(meta_dir, 'config-options')) scan_opt_defs(os.path.join(meta_dir, 'feature-options')) scan_use_tags() scan_tags_meta(os.path.join(meta_dir, 'tags.yaml')) - print('Scanned %d DUK_OPT_xxx, %d DUK_USE_XXX, %d helper snippets' % \ - (len(opt_defs.keys()), len(use_defs.keys()), len(helper_snippets))) + print('%s, scanned %d DUK_OPT_xxx, %d DUK_USE_XXX, %d helper snippets' % \ + (metadata_src_text, len(opt_defs.keys()), len(use_defs.keys()), len(helper_snippets))) #print('Tags: %r' % use_tags_list) if len(args) == 0: raise Exception('missing command') cmd = args[0] + # Compatibility with Duktape 1.3 if cmd == 'autodetect-header': - cmd = 'autodetect-header-legacy' + cmd = 'duk-config-header' + if cmd == 'barebones-header': + cmd = 'duk-config-header' - if cmd == 'autodetect-header-legacy': - # Generate a duk_config.h similar to Duktape 1.2 feature detection, - # based on manually written monolithic snippets. - # To be replaced by modular header. - result = generate_autodetect_duk_config_header(opts, meta_dir) - with open(opts.output, 'wb') as f: - f.write(result) - elif cmd == 'autodetect-header-modular': - # Generate a duk_config.h similar to Duktape 1.2 feature detection. - # Platform, architecture, and compiler can each be either autodetected - # or specified by user. Generated header is based on modular snippets - # rather than a monolithic platform detection header. - result = generate_autodetect_duk_config_header_modular(opts, meta_dir) - with open(opts.output, 'wb') as f: - f.write(result) - elif cmd == 'barebones-header': - # Generate a duk_config.h with default options for a specific platform, - # compiler, and architecture. - result = generate_barebones_duk_config_header(opts, meta_dir) + if cmd == 'duk-config-header': + # Generate a duk_config.h header with platform, compiler, and + # architecture either autodetected (default) or specified by + # user. Support for autogenerated DUK_OPT_xxx flags is also + # selected by user. + result = generate_duk_config_header(opts, meta_dir) with open(opts.output, 'wb') as f: f.write(result) elif cmd == 'feature-documentation': diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/genconfig_metadata.tar.gz b/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/genconfig_metadata.tar.gz new file mode 100644 index 000000000..c34b2ef10 Binary files /dev/null and b/ceph/src/civetweb/src/third_party/duktape-1.5.2/config/genconfig_metadata.tar.gz differ diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/Makefile b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/Makefile similarity index 69% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/Makefile rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/Makefile index a85bc012b..50740b549 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/Makefile +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/Makefile @@ -1,4 +1,5 @@ NODE:=$(shell which nodejs node | head -1) +DUKLUV:=dukluv # Try to get a useful default --source-dirs which works both in the Duktape # repo and in the distributable. We don't want to add '..' because it would @@ -14,11 +15,23 @@ all: run .PHONY: run run: node_modules static/socket.io-1.2.0.js static/jquery-1.11.1.min.js static/reset.css static/jquery-ui.min.js static/jquery-ui.min.css static/images - $(NODE) duk_debug.js --source-dirs=$(SOURCEDIRS) + "$(NODE)" duk_debug.js --source-dirs=$(SOURCEDIRS) + +rundebug: node_modules static/socket.io-1.2.0.js static/jquery-1.11.1.min.js static/reset.css static/jquery-ui.min.js static/jquery-ui.min.css static/images + "$(NODE)" duk_debug.js --source-dirs=$(SOURCEDIRS) --verbose --log-messages /tmp/dukdebug-messages --dump-debug-pretty /tmp/dukdebug-pretty + +.PHONY: runproxynodejs +runproxynodejs: node_modules static/socket.io-1.2.0.js static/jquery-1.11.1.min.js static/reset.css static/jquery-ui.min.js static/jquery-ui.min.css static/images + @echo "Running Node.js based debug proxy" + "$(NODE)" duk_debug.js --json-proxy + +.PHONY: runproxydukluv +runproxydukluv: duk_debug_meta.json + @echo "Running Dukluv based debug proxy (you may need to edit DUKLUV in the Makefile)" + "$(DUKLUV)" duk_debug_proxy.js --log-level 2 --metadata duk_debug_meta.json --readable-numbers .PHONY: runproxy -runproxy: node_modules static/socket.io-1.2.0.js static/jquery-1.11.1.min.js static/reset.css static/jquery-ui.min.js static/jquery-ui.min.css static/images - $(NODE) duk_debug.js --json-proxy +runproxy: runproxydukluv .PHONY: clean clean: @@ -35,12 +48,20 @@ clean: @rm -f jquery-ui-1.11.2.zip @rm -rf jquery-ui-1.11.2 @rm -rf node_modules + @rm -f duk_debug_meta.json node_modules: npm install +duk_debug_meta.json: + python merge_debug_meta.py --output $@ \ + --class-names duk_classnames.yaml \ + --opcodes duk_opcodes.yaml \ + --debug-commands duk_debugcommands.yaml \ + --debug-errors duk_debugerrors.yaml + static/socket.io-1.2.0.js: - wget -O $@ https://cdn.socket.io/socket.io-1.2.0.js + wget -O $@ http://cdn.socket.io/socket.io-1.2.0.js static/jquery-1.11.1.min.js: wget -O $@ http://code.jquery.com/jquery-1.11.1.min.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/README.rst similarity index 59% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/README.rst index 8a82d65dc..f60b3506a 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/README.rst +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/README.rst @@ -6,7 +6,8 @@ Overview ======== Debugger web UI which connects to the Duktape command line tool or any other -target supporting the example TCP transport (``examples/debug-trans-socket``). +target supporting the example TCP transport (``examples/debug-trans-socket``) +on Unix and Windows. Also provides a JSON debug proxy with a JSON mapping for the Duktape debug protocol. @@ -24,7 +25,7 @@ Some prerequisites: the required packages. Compile Duktape command line tool with debugger support (for further options -see ``doc/feature-options.rst``): +see http://wiki.duktape.org/FeatureOptions.html): * ``DUK_OPT_DEBUGGER_SUPPORT`` @@ -75,10 +76,125 @@ web UI. Using the JSON debug proxy ========================== -A JSON debug proxy is also provided by ``duk_debug.js``:: +There are two JSON debug proxy implementations: one implemented in DukLuv +and another in Node.js. - # Same prerequisites as above - $ make runproxy +DukLuv JSON proxy +----------------- + +DukLuv (https://github.com/creationix/dukluv) is a small and portable event +loop based on LibUV and Duktape with MIT license (like Duktape). As such it's +easy to embed in a custom debug client: you just include the DukLuv executable +and the JSON proxy source file in your debug client. + +Install DukLuv: + +* Ensure ``cmake`` is installed + +* ``git clone https://github.com/creationix/dukluv.git`` + +* ``git submodule init; git submodule update`` + +* ``make`` + +* Binary should appear in: + + - ``./build/dukluv`` on Linux + + - ``.\build\Debug\dukluv.exe`` on Windows + +Run the proxy:: + + # Using Makefile; autogenerates duk_debug_meta.json + # (You may need to edit DUKLUV in Makefile to point to your DukLuv) + $ make runproxydukluv + + # Manually: see "dukluv duk_debug_proxy.js --help" for help + $ .../path/to/dukluv duk_debug_proxy.js + +Start Duktape command line (or whatever your target is):: + + $ cd /tests/ecmascript/ + $ ../../duk --debugger test-dev-mandel2-func.js + +Now connect to the proxy using e.g. telnet:: + + $ telnet localhost 9093 + +The proxy will then connect to the target and you can start issuing commands:: + + $ telnet localhost 9093 + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + {"notify":"_TargetConnecting","args":["127.0.0.1",9091]} + {"notify":"_TargetConnected","args":["1 10499 v1.4.0-140-gc9a6c7c duk command built from Duktape repo"]} + {"notify":"Status","command":1,"args":[1,"test-dev-mandel2-func.js","global",58,0]} + {"request":"BasicInfo"} + {"reply":true,"args":[10499,"v1.4.0-140-gc9a6c7c","duk command built from Duktape repo",1]} + {"request":"Eval","args":["print('Hello world!'); 123;"]} + {"notify":"Print","command":2,"args":["Hello world!\n"]} + {"reply":true,"args":[0,{"type":"number","data":"405ec00000000000"}]} + [...] + +The proxy log provides dumps both JSON and dvalue binary traffic which is +quite useful in development:: + + $ make runproxydukluv + Running Dukluv based debug proxy + "dukluv" duk_debug_proxy.js --log-level 2 --metadata duk_debug_meta.json + 2016-02-17T13:59:42.308Z INF Proxy: Read proxy metadata from duk_debug_meta.json + 2016-02-17T13:59:42.325Z INF Proxy: Listening for incoming JSON debug connection on 0.0.0.0:9093, target is 127.0.0.1:9091 + 2016-02-17T13:59:47.994Z INF Proxy: JSON proxy client connected + 2016-02-17T13:59:47.994Z INF Proxy: Connecting to debug target at 127.0.0.1:9091 + 2016-02-17T13:59:47.994Z INF Proxy: PROXY --> CLIENT: {"notify":"_TargetConnecting","args":["127.0.0.1",9091]} + 2016-02-17T13:59:47.994Z INF Proxy: Connected to debug target at 127.0.0.1:9091 + 2016-02-17T13:59:48.003Z INF Proxy: PROXY --> CLIENT: {"notify":"_TargetConnected","args":["1 10499 v1.4.0-140-gc9a6c7c duk command built from Duktape repo"]} + 2016-02-17T13:59:48.003Z INF Proxy: Target handshake: {"line":"1 10499 v1.4.0-140-gc9a6c7c duk command built from Duktape repo","protocolVersion":1,"text":"10499 v1.4.0-140-gc9a6c7c duk command built from Duktape repo","dukVersion":"1","dukGitDescribe":"10499","targetString":"v1.4.0-140-gc9a6c7c"} + 2016-02-17T13:59:48.151Z INF Proxy: PROXY <-- TARGET: |04| + 2016-02-17T13:59:48.152Z INF Proxy: PROXY <-- TARGET: |81| + 2016-02-17T13:59:48.152Z INF Proxy: PROXY <-- TARGET: |81| + 2016-02-17T13:59:48.160Z INF Proxy: PROXY <-- TARGET: |78746573742d6465762d6d616e64656c322d66756e632e6a73| + 2016-02-17T13:59:48.161Z INF Proxy: PROXY <-- TARGET: |66676c6f62616c| + 2016-02-17T13:59:48.165Z INF Proxy: PROXY <-- TARGET: |ba| + 2016-02-17T13:59:48.165Z INF Proxy: PROXY <-- TARGET: |80| + 2016-02-17T13:59:48.165Z INF Proxy: PROXY <-- TARGET: |00| + 2016-02-17T13:59:48.165Z INF Proxy: PROXY --> CLIENT: {"notify":"Status","command":1,"args":[1,"test-dev-mandel2-func.js","global",58,0]} + 2016-02-17T13:59:51.289Z INF Proxy: PROXY <-- CLIENT: {"request":"BasicInfo"} + 2016-02-17T13:59:51.289Z INF Proxy: PROXY --> TARGET: |01| + 2016-02-17T13:59:51.289Z INF Proxy: PROXY --> TARGET: |90| + 2016-02-17T13:59:51.289Z INF Proxy: PROXY --> TARGET: |00| + 2016-02-17T13:59:51.291Z INF Proxy: PROXY <-- TARGET: |02| + 2016-02-17T13:59:51.291Z INF Proxy: PROXY <-- TARGET: |e903| + 2016-02-17T13:59:51.292Z INF Proxy: PROXY <-- TARGET: |7376312e342e302d3134302d6763396136633763| + 2016-02-17T13:59:51.293Z INF Proxy: PROXY <-- TARGET: |12002364756b20636f6d6d616e64206275696c742066726f6d2044756b74617065207265706f| + 2016-02-17T13:59:51.293Z INF Proxy: PROXY <-- TARGET: |81| + 2016-02-17T13:59:51.293Z INF Proxy: PROXY <-- TARGET: |00| + 2016-02-17T13:59:51.293Z INF Proxy: PROXY --> CLIENT: {"reply":true,"args":[10499,"v1.4.0-140-gc9a6c7c","duk command built from Duktape repo",1]} + 2016-02-17T14:00:06.105Z INF Proxy: PROXY <-- CLIENT: {"request":"Eval","args":["print('Hello world!'); 123;"]} + 2016-02-17T14:00:06.105Z INF Proxy: PROXY --> TARGET: |01| + 2016-02-17T14:00:06.105Z INF Proxy: PROXY --> TARGET: |9e| + 2016-02-17T14:00:06.105Z INF Proxy: PROXY --> TARGET: |7b7072696e74282748656c6c6f20776f726c642127293b203132333b| + 2016-02-17T14:00:06.105Z INF Proxy: PROXY --> TARGET: |00| + 2016-02-17T14:00:06.167Z INF Proxy: PROXY <-- TARGET: |04| + 2016-02-17T14:00:06.167Z INF Proxy: PROXY <-- TARGET: |82| + 2016-02-17T14:00:06.167Z INF Proxy: PROXY <-- TARGET: |6d48656c6c6f20776f726c64210a| + 2016-02-17T14:00:06.168Z INF Proxy: PROXY <-- TARGET: |00| + 2016-02-17T14:00:06.168Z INF Proxy: PROXY --> CLIENT: {"notify":"Print","command":2,"args":["Hello world!\n"]} + 2016-02-17T14:00:06.171Z INF Proxy: PROXY <-- TARGET: |02| + 2016-02-17T14:00:06.171Z INF Proxy: PROXY <-- TARGET: |80| + 2016-02-17T14:00:06.173Z INF Proxy: PROXY <-- TARGET: |1a405ec00000000000| + 2016-02-17T14:00:06.173Z INF Proxy: PROXY <-- TARGET: |00| + 2016-02-17T14:00:06.174Z INF Proxy: PROXY --> CLIENT: {"reply":true,"args":[0,{"type":"number","data":"405ec00000000000"}]} + [...] + +Node.js JSON proxy +------------------ + +A Node.js-based JSON debug proxy is also provided by ``duk_debug.js``:: + + # Same prerequisites as for running the debug client + $ make runproxynodejs Start Duktape command line (or whatever your target is):: @@ -94,7 +210,7 @@ readability and are not part of the stream:: Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. - <-- {"notify":"_Connected","args":["1 10199 v1.1.0-275-gbd4d610-dirty duk command built from Duktape repo"]} + <-- {"notify":"_TargetConnected","args":["1 10199 v1.1.0-275-gbd4d610-dirty duk command built from Duktape repo"]} <-- {"notify":"Status","command":1,"args":[1,"test-dev-mandel2-func.js","global",58,0]} --> {"request":"BasicInfo"} <-- {"reply":true,"args":[10199,"v1.1.0-275-gbd4d610-dirty","duk command built from Duktape repo",1]} diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_classnames.yaml b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_classnames.yaml new file mode 100644 index 000000000..9fd5098a5 --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_classnames.yaml @@ -0,0 +1,32 @@ +# Must match C header. +class_names: + - unused + - Arguments + - Array + - Boolean + - Date + - Error + - Function + - JSON + - Math + - Number + - Object + - RegExp + - String + - global + - ObjEnv + - DecEnv + - Buffer + - Pointer + - Thread + - ArrayBuffer + - DataView + - Int8Array + - Uint8Array + - Uint8ClampedArray + - Int16Array + - Uint16Array + - Int32Array + - Uint32Array + - Float32Array + - Float64Array diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/duk_debug.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debug.js similarity index 95% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/duk_debug.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debug.js index 5a294095b..ab0623fa7 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/duk_debug.js +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debug.js @@ -53,6 +53,8 @@ var CMD_STATUS = 0x01; var CMD_PRINT = 0x02; var CMD_ALERT = 0x03; var CMD_LOG = 0x04; +var CMD_THROW = 0x05; +var CMD_DETACHING = 0x06; // Commands initiated by the debug client (= us) var CMD_BASICINFO = 0x10; @@ -89,11 +91,16 @@ var DVAL_NFY = { type: 'nfy' }; // String map for commands (debug dumping). A single map works (instead of // separate maps for each direction) because command numbers don't currently -// overlap. -var debugCommandNames = yaml.load('duk_debugcommands.yaml'); - -// Map debug command names to numbers. -var debugCommandNumbers = {}; +// overlap. So merge the YAML metadata. +var debugCommandMeta = yaml.load('duk_debugcommands.yaml'); +var debugCommandNames = []; // list of command names, merged client/target +debugCommandMeta.target_commands.forEach(function (k, i) { + debugCommandNames[i] = k; +}); +debugCommandMeta.client_commands.forEach(function (k, i) { // override + debugCommandNames[i] = k; +}); +var debugCommandNumbers = {}; // map from (merged) command name to number debugCommandNames.forEach(function (k, i) { debugCommandNumbers[k] = i; }); @@ -104,10 +111,11 @@ var DUK_HTYPE_OBJECT = 2; var DUK_HTYPE_BUFFER = 3; // Duktape internal class numbers, must match C headers -var dukClassNames = yaml.load('duk_classnames.yaml'); +var dukClassNameMeta = yaml.load('duk_classnames.yaml'); +var dukClassNames = dukClassNameMeta.class_names; // Bytecode opcode/extraop metadata -var dukOpcodes = yaml.load('duk_opcodes.yaml') +var dukOpcodes = yaml.load('duk_opcodes.yaml'); if (dukOpcodes.opcodes.length != 64) { throw new Error('opcode metadata length incorrect'); } @@ -158,7 +166,7 @@ function writeDebugStringToBuffer(str, buf, off) { var i, n; for (i = 0, n = str.length; i < n; i++) { - buf[off + i] = str.charCodeAt(i) & 0xff; + buf[off + i] = str.charCodeAt(i) & 0xff; // truncate higher bits } } @@ -193,11 +201,11 @@ function prettyDebugValue(x) { * and signed zeroes properly. */ function prettyUiNumber(x) { - if (x === 1/0) { return 'Infinity'; } - if (x === -1/0) { return '-Infinity'; } + if (x === 1 / 0) { return 'Infinity'; } + if (x === -1 / 0) { return '-Infinity'; } if (Number.isNaN(x)) { return 'NaN'; } - if (x === 0 && 1/x > 0) { return '0'; } - if (x === 0 && 1/x < 0) { return '-0'; } + if (x === 0 && 1 / x > 0) { return '0'; } + if (x === 0 && 1 / x < 0) { return '-0'; } return x.toString(); } @@ -425,7 +433,7 @@ RateLimited.prototype.trigger = function () { function SourceFileManager(directories) { this.directories = directories; - this.extensions = { '.js': true, '.jsm': true }; + this.extensions = { '.js': true, '.jsm': true }; this.files; } @@ -713,12 +721,12 @@ function DebugProtocolParser(inputStream, if (buf.length >= 9) { v = new Buffer(8); buf.copy(v, 0, 1, 9); - v = { type: 'number', data: v.toString('hex') } + v = { type: 'number', data: v.toString('hex') }; if (_this.readableNumberValue) { - // The _value key should not be used programmatically, + // The value key should not be used programmatically, // it is just there to make the dumps more readable. - v._value = buf.readDoubleBE(1); + v.value = buf.readDoubleBE(1); } consume(9); } @@ -1067,7 +1075,7 @@ Debugger.prototype.decodeBytecodeFromBuffer = function (buf, consts, funcs) { comments = []; if (op.args) { for (j = 0, m = op.args.length; j < m; j++) { - switch(op.args[j]) { + switch (op.args[j]) { case 'A_R': args.push('r' + ((ins >>> 6) & 0xff)); break; case 'A_RI': args.push('r' + ((ins >>> 6) & 0xff) + '(indirect)'); break; case 'A_C': args.push('c' + ((ins >>> 6) & 0xff)); break; @@ -1204,30 +1212,30 @@ Debugger.prototype.sendBasicInfoRequest = function () { }); }; -Debugger.prototype.sendGetVarRequest = function (varname) { +Debugger.prototype.sendGetVarRequest = function (varname, level) { var _this = this; - return this.sendRequest([ DVAL_REQ, CMD_GETVAR, varname, DVAL_EOM ]).then(function (msg) { + return this.sendRequest([ DVAL_REQ, CMD_GETVAR, varname, (typeof level === 'number' ? level : -1), DVAL_EOM ]).then(function (msg) { return { found: msg[1] === 1, value: msg[2] }; }); }; -Debugger.prototype.sendPutVarRequest = function (varname, varvalue) { +Debugger.prototype.sendPutVarRequest = function (varname, varvalue, level) { var _this = this; - return this.sendRequest([ DVAL_REQ, CMD_PUTVAR, varname, varvalue, DVAL_EOM ]); + return this.sendRequest([ DVAL_REQ, CMD_PUTVAR, varname, varvalue, (typeof level === 'number' ? level : -1), DVAL_EOM ]); }; Debugger.prototype.sendInvalidCommandTestRequest = function () { // Intentional invalid command var _this = this; return this.sendRequest([ DVAL_REQ, 0xdeadbeef, DVAL_EOM ]); -} +}; Debugger.prototype.sendStatusRequest = function () { // Send a status request to trigger a status notify, result is ignored: // target sends a status notify instead of a meaningful reply var _this = this; return this.sendRequest([ DVAL_REQ, CMD_TRIGGERSTATUS, DVAL_EOM ]); -} +}; Debugger.prototype.sendBreakpointListRequest = function () { var _this = this; @@ -1245,9 +1253,9 @@ Debugger.prototype.sendBreakpointListRequest = function () { }); }; -Debugger.prototype.sendGetLocalsRequest = function () { +Debugger.prototype.sendGetLocalsRequest = function (level) { var _this = this; - return this.sendRequest([ DVAL_REQ, CMD_GETLOCALS, DVAL_EOM ]).then(function (msg) { + return this.sendRequest([ DVAL_REQ, CMD_GETLOCALS, (typeof level === 'number' ? level : -1), DVAL_EOM ]).then(function (msg) { var i; var locals = []; @@ -1308,9 +1316,9 @@ Debugger.prototype.sendResumeRequest = function () { return this.sendRequest([ DVAL_REQ, CMD_RESUME, DVAL_EOM ]); }; -Debugger.prototype.sendEvalRequest = function (evalInput) { +Debugger.prototype.sendEvalRequest = function (evalInput, level) { var _this = this; - return this.sendRequest([ DVAL_REQ, CMD_EVAL, evalInput, DVAL_EOM ]).then(function (msg) { + return this.sendRequest([ DVAL_REQ, CMD_EVAL, evalInput, (typeof level === 'number' ? level : -1), DVAL_EOM ]).then(function (msg) { return { error: msg[1] === 1 /*error*/, value: msg[2] }; }); }; @@ -1402,6 +1410,7 @@ Debugger.prototype.sendGetBytecodeRequest = function () { var bcode; var preformatted; var ret; + var idxPreformattedInstructions; //console.log(JSON.stringify(msg)); @@ -1431,6 +1440,7 @@ Debugger.prototype.sendGetBytecodeRequest = function () { preformatted.push('; c' + i + ' ' + JSON.stringify(v)); }); preformatted.push(''); + idxPreformattedInstructions = preformatted.length; bcode.forEach(function (v) { preformatted.push(v.str); }); @@ -1440,7 +1450,8 @@ Debugger.prototype.sendGetBytecodeRequest = function () { constants: consts, functions: funcs, bytecode: bcode, - preformatted: preformatted + preformatted: preformatted, + idxPreformattedInstructions: idxPreformattedInstructions }; return ret; @@ -1696,9 +1707,15 @@ Debugger.prototype.processDebugMessage = function (msg) { this.uiMessage('alert', prettyUiStringUnquoted(msg[2], UI_MESSAGE_CLIPLEN)); } else if (msg[1] === CMD_LOG) { this.uiMessage({ type: 'log', level: msg[2], message: prettyUiStringUnquoted(msg[3], UI_MESSAGE_CLIPLEN) }); + } else if (msg[1] === CMD_THROW) { + this.uiMessage({ type: 'throw', fatal: msg[2], message: (msg[2] ? 'UNCAUGHT: ' : 'THROW: ') + prettyUiStringUnquoted(msg[3], UI_MESSAGE_CLIPLEN), fileName: msg[4], lineNumber: msg[5] }); + } else if (msg[1] === CMD_DETACHING) { + this.uiMessage({ type: 'detaching', reason: msg[2], message: 'DETACH: ' + (msg.length >= 5 ? prettyUiStringUnquoted(msg[3]) : 'detaching') }); } else { - console.log('Unknown notify, dropping connection: ' + prettyDebugMessage(msg)); - this.targetStream.destroy(); + // Ignore unknown notify messages + console.log('Unknown notify, ignoring: ' + prettyDebugMessage(msg)); + + //this.targetStream.destroy(); } } else { console.log('Invalid initial dvalue, dropping connection: ' + prettyDebugMessage(msg)); @@ -1733,7 +1750,7 @@ Debugger.prototype.run = function () { // while a previous request is pending. The flag-based approach is // quite awkward. Rework to use promises. - switch(sendRound) { + switch (sendRound) { case 0: if (!statusPending) { statusPending = true; @@ -1946,14 +1963,18 @@ DebugWebServer.prototype.handleNewSocketIoConnection = function (socket) { // msg.input is a proper Unicode strings here, and needs to be // converted into a protocol string (U+0000...U+00FF). var input = stringToDebugString(msg.input); - _this.dbg.sendEvalRequest(input).then(function (v) { + _this.dbg.sendEvalRequest(input, msg.level).then(function (v) { socket.emit('eval-result', { error: v.error, result: prettyUiDebugValue(v.value, EVAL_CLIPLEN) }); }); // An eval call quite possibly changes the local variables so always - // re-read locals afterwards. We don't need to wait for eval() to + // re-read locals afterwards. We don't need to wait for Eval to // complete here; the requests will pipeline automatically and be // executed in order. + + // XXX: move this to the web UI so that the UI can control what + // locals are listed (or perhaps show locals for all levels with + // an expandable tree view). _this.dbg.sendGetLocalsRequest(); }); @@ -1961,7 +1982,7 @@ DebugWebServer.prototype.handleNewSocketIoConnection = function (socket) { // msg.varname is a proper Unicode strings here, and needs to be // converted into a protocol string (U+0000...U+00FF). var varname = stringToDebugString(msg.varname); - _this.dbg.sendGetVarRequest(varname) + _this.dbg.sendGetVarRequest(varname, msg.level) .then(function (v) { socket.emit('getvar-result', { found: v.found, result: prettyUiDebugValue(v.value, GETVAR_CLIPLEN) }); }); @@ -1979,15 +2000,17 @@ DebugWebServer.prototype.handleNewSocketIoConnection = function (socket) { varvalue = stringToDebugString(msg.varvalue); } - _this.dbg.sendPutVarRequest(varname, varvalue) + _this.dbg.sendPutVarRequest(varname, varvalue, msg.level) .then(function (v) { console.log('putvar done'); // XXX: signal success to UI? }); // A PutVar call quite possibly changes the local variables so always - // re-read locals afterwards. We don't need to wait for eval() to + // re-read locals afterwards. We don't need to wait for PutVar to // complete here; the requests will pipeline automatically and be // executed in order. + + // XXX: make the client do this? _this.dbg.sendGetLocalsRequest(); }); @@ -2143,14 +2166,16 @@ function DebugProxy(serverPort) { this.dval_err = formatDebugValue(DVAL_ERR); } -DebugProxy.prototype.determineCommandNumber = function (cmdString, cmdNumber) { +DebugProxy.prototype.determineCommandNumber = function (cmdName, cmdNumber) { var ret; - if (typeof cmdString === 'string') { - ret = debugCommandNumbers[cmdString]; + if (typeof cmdName === 'string') { + ret = debugCommandNumbers[cmdName]; + } else if (typeof cmdName === 'number') { + ret = cmdName; } ret = ret || cmdNumber; if (typeof ret !== 'number') { - throw Error('cannot figure out command number for "' + cmdString + '" (' + cmdNumber + ')'); + throw Error('cannot figure out command number for "' + cmdName + '" (' + cmdNumber + ')'); } return ret; }; @@ -2282,7 +2307,7 @@ DebugProxy.prototype.connectToTarget = function () { null // console logging is done at a higher level to match request/response ); - // Don't add a '_value' key to numbers. + // Don't add a 'value' key to numbers. this.inputParser.readableNumberValue = false; this.inputParser.on('transport-close', function () { @@ -2310,7 +2335,7 @@ DebugProxy.prototype.connectToTarget = function () { console.log('Debug version identification:', msg.versionIdentification); _this.writeJson({ - notify: '_Connected', + notify: '_TargetConnected', args: [ msg.versionIdentification ] // raw identification string }); @@ -2326,9 +2351,9 @@ DebugProxy.prototype.connectToTarget = function () { if (typeof msg[0] !== 'object' || msg[0] === null) { throw new Error('unexpected initial dvalue: ' + msg[0]); - } else if (msg.type === 'eom') { + } else if (msg[0].type === 'eom') { throw new Error('unexpected initial dvalue: ' + msg[0]); - } else if (msg.type === 'req') { + } else if (msg[0].type === 'req') { if (typeof msg[1] !== 'number') { throw new Error('unexpected request command number: ' + msg[1]); } @@ -2336,19 +2361,19 @@ DebugProxy.prototype.connectToTarget = function () { request: _this.commandNumberToString(msg[1]), command: msg[1], args: msg.slice(2, msg.length - 1) - } + }; _this.writeJson(t); } else if (msg[0].type === 'rep') { t = { reply: true, args: msg.slice(1, msg.length - 1) - } + }; _this.writeJson(t); } else if (msg[0].type === 'err') { t = { error: true, args: msg.slice(1, msg.length - 1) - } + }; _this.writeJson(t); } else if (msg[0].type === 'nfy') { if (typeof msg[1] !== 'number') { @@ -2358,7 +2383,7 @@ DebugProxy.prototype.connectToTarget = function () { notify: _this.commandNumberToString(msg[1]), command: msg[1], args: msg.slice(2, msg.length - 1) - } + }; _this.writeJson(t); } else { throw new Error('unexpected initial dvalue: ' + msg[0]); diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debug_meta.json b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debug_meta.json new file mode 100644 index 000000000..41de1c2f8 --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debug_meta.json @@ -0,0 +1,1497 @@ +{ + "opcodes": [ + { + "args": [ + "A_R", + "BC_R" + ], + "name": "LDREG" + }, + { + "args": [ + "A_R", + "BC_R" + ], + "name": "STREG" + }, + { + "args": [ + "A_R", + "BC_C" + ], + "name": "LDCONST" + }, + { + "args": [ + "A_R", + "BC_LDINT" + ], + "name": "LDINT" + }, + { + "args": [ + "A_R", + "BC_LDINTX" + ], + "name": "LDINTX" + }, + { + "args": [ + "A_R", + "B_R", + "C_I" + ], + "name": "MPUTOBJ" + }, + { + "args": [ + "A_R", + "B_RI", + "C_I" + ], + "name": "MPUTOBJI" + }, + { + "args": [ + "A_R", + "B_R", + "C_I" + ], + "name": "MPUTARR" + }, + { + "args": [ + "A_R", + "B_RI", + "C_I" + ], + "name": "MPUTARRI" + }, + { + "args": [ + "B_R", + "C_I" + ], + "name": "NEW" + }, + { + "args": [ + "B_RI", + "C_I" + ], + "name": "NEWI" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "REGEXP" + }, + { + "args": [ + "A_R", + "B_R" + ], + "name": "CSREG" + }, + { + "args": [ + "A_RI", + "B_R" + ], + "name": "CSREGI" + }, + { + "args": [ + "A_R", + "BC_C" + ], + "name": "GETVAR" + }, + { + "args": [ + "A_R", + "BC_C" + ], + "name": "PUTVAR" + }, + { + "args": [ + "A_H", + "B_RC", + "C_RC" + ], + "flags": [ + { + "mask": 64, + "name": "writable" + }, + { + "mask": 128, + "name": "enumerable" + }, + { + "mask": 256, + "name": "configurable" + }, + { + "mask": 512, + "name": "accessor" + }, + { + "mask": 1024, + "name": "undef_value" + }, + { + "mask": 2048, + "name": "func_decl" + } + ], + "name": "DECLVAR" + }, + { + "args": [ + "A_R", + "B_RC" + ], + "name": "DELVAR" + }, + { + "args": [ + "A_R", + "B_RC" + ], + "name": "CSVAR" + }, + { + "args": [ + "A_RI", + "B_RC" + ], + "name": "CSVARI" + }, + { + "args": [ + "A_R", + "BC_I" + ], + "name": "CLOSURE" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "GETPROP" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "PUTPROP" + }, + { + "args": [ + "A_R", + "B_R", + "C_RC" + ], + "name": "DELPROP" + }, + { + "args": [ + "A_R", + "B_R", + "C_RC" + ], + "name": "CSPROP" + }, + { + "args": [ + "A_RI", + "B_R", + "C_RC" + ], + "name": "CSPROPI" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "ADD" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "SUB" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "MUL" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "DIV" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "MOD" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "BAND" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "BOR" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "BXOR" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "BASL" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "BLSR" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "BASR" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "EQ" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "NEQ" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "SEQ" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "SNEQ" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "GT" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "GE" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "LT" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "LE" + }, + { + "args": [ + "A_B", + "B_RC" + ], + "name": "IF" + }, + { + "args": [ + "ABC_JUMP" + ], + "name": "JUMP" + }, + { + "args": [ + "A_H", + "B_RC" + ], + "flags": [ + { + "mask": 64, + "name": "have_retval" + } + ], + "name": "RETURN" + }, + { + "args": [ + "A_H", + "B_R", + "C_I" + ], + "flags": [ + { + "mask": 64, + "name": "tailcall" + }, + { + "mask": 128, + "name": "evalcall" + } + ], + "name": "CALL" + }, + { + "args": [ + "A_H", + "B_RI", + "C_I" + ], + "name": "CALLI" + }, + { + "args": [ + "A_H", + "BC_R" + ], + "flags": [ + { + "mask": 64, + "name": "have_catch" + }, + { + "mask": 128, + "name": "have_finally" + }, + { + "mask": 256, + "name": "catch_binding" + }, + { + "mask": 512, + "name": "with_binding" + } + ], + "name": "TRYCATCH" + }, + { + "name": "EXTRA", + "extra": true + }, + { + "args": [ + "A_R", + "BC_R" + ], + "name": "PREINCR" + }, + { + "args": [ + "A_R", + "BC_R" + ], + "name": "PREDECR" + }, + { + "args": [ + "A_R", + "BC_R" + ], + "name": "POSTINCR" + }, + { + "args": [ + "A_R", + "BC_R" + ], + "name": "POSTDECR" + }, + { + "args": [ + "A_R", + "BC_C" + ], + "name": "PREINCV" + }, + { + "args": [ + "A_R", + "BC_C" + ], + "name": "PREDECV" + }, + { + "args": [ + "A_R", + "BC_C" + ], + "name": "POSTINCV" + }, + { + "args": [ + "A_R", + "BC_C" + ], + "name": "POSTDECV" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "PREINCP" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "PREDECP" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "POSTINCP" + }, + { + "args": [ + "A_R", + "B_RC", + "C_RC" + ], + "name": "POSTDECP" + } + ], + "client_commands": [ + "Reserved_0", + "Status", + "Print", + "Alert", + "Log", + "Throw", + "Detaching", + "AppNotify" + ], + "extra": [ + { + "name": "NOP" + }, + { + "args": [ + "BC_I" + ], + "name": "INVALID" + }, + { + "args": [ + "BC_R" + ], + "name": "LDTHIS" + }, + { + "args": [ + "BC_R" + ], + "name": "LDUNDEF" + }, + { + "args": [ + "BC_R" + ], + "name": "LDNULL" + }, + { + "args": [ + "BC_R" + ], + "name": "LDTRUE" + }, + { + "args": [ + "BC_R" + ], + "name": "LDFALSE" + }, + { + "args": [ + "B_R" + ], + "name": "NEWOBJ" + }, + { + "args": [ + "B_R" + ], + "name": "NEWARR" + }, + { + "args": [ + "B_R", + "C_R" + ], + "name": "SETALEN" + }, + { + "args": [ + "BC_R" + ], + "name": "TYPEOF" + }, + { + "args": [ + "B_R", + "C_RC" + ], + "name": "TYPEOFID" + }, + { + "args": [ + "B_R", + "C_R" + ], + "name": "INITENUM" + }, + { + "args": [ + "B_R", + "C_R" + ], + "name": "NEXTENUM" + }, + { + "args": [ + "B_R", + "C_R" + ], + "name": "INITSET" + }, + { + "args": [ + "B_R", + "C_RI" + ], + "name": "INITSETI" + }, + { + "args": [ + "B_R", + "C_RI" + ], + "name": "INITGET" + }, + { + "args": [ + "B_R", + "C_RI" + ], + "name": "INITGETI" + }, + { + "name": "ENDTRY" + }, + { + "name": "ENDCATCH" + }, + { + "name": "ENDFIN" + }, + { + "args": [ + "BC_R" + ], + "name": "THROW" + }, + { + "name": "INVLHS" + }, + { + "args": [ + "BC_R" + ], + "name": "UNM" + }, + { + "args": [ + "BC_R" + ], + "name": "UNP" + }, + { + "name": "DEBUGGER" + }, + { + "args": [ + "BC_I" + ], + "name": "BREAK" + }, + { + "args": [ + "BC_I" + ], + "name": "CONTINUE" + }, + { + "args": [ + "BC_R" + ], + "name": "BNOT" + }, + { + "args": [ + "BC_R" + ], + "name": "LNOT" + }, + { + "args": [ + "B_R", + "C_RC" + ], + "name": "INSTOF" + }, + { + "args": [ + "B_R", + "C_RC" + ], + "name": "IN" + }, + { + "args": [ + "BC_I" + ], + "name": "LABEL" + }, + { + "args": [ + "BC_I" + ], + "name": "ENDLABEL" + }, + { + "name": "EXTRA34" + }, + { + "name": "EXTRA35" + }, + { + "name": "EXTRA36" + }, + { + "name": "EXTRA37" + }, + { + "name": "EXTRA38" + }, + { + "name": "EXTRA39" + }, + { + "name": "EXTRA40" + }, + { + "name": "EXTRA41" + }, + { + "name": "EXTRA42" + }, + { + "name": "EXTRA43" + }, + { + "name": "EXTRA44" + }, + { + "name": "EXTRA45" + }, + { + "name": "EXTRA46" + }, + { + "name": "EXTRA47" + }, + { + "name": "EXTRA48" + }, + { + "name": "EXTRA49" + }, + { + "name": "EXTRA50" + }, + { + "name": "EXTRA51" + }, + { + "name": "EXTRA52" + }, + { + "name": "EXTRA53" + }, + { + "name": "EXTRA54" + }, + { + "name": "EXTRA55" + }, + { + "name": "EXTRA56" + }, + { + "name": "EXTRA57" + }, + { + "name": "EXTRA58" + }, + { + "name": "EXTRA59" + }, + { + "name": "EXTRA60" + }, + { + "name": "EXTRA61" + }, + { + "name": "EXTRA62" + }, + { + "name": "EXTRA63" + }, + { + "name": "EXTRA64" + }, + { + "name": "EXTRA65" + }, + { + "name": "EXTRA66" + }, + { + "name": "EXTRA67" + }, + { + "name": "EXTRA68" + }, + { + "name": "EXTRA69" + }, + { + "name": "EXTRA70" + }, + { + "name": "EXTRA71" + }, + { + "name": "EXTRA72" + }, + { + "name": "EXTRA73" + }, + { + "name": "EXTRA74" + }, + { + "name": "EXTRA75" + }, + { + "name": "EXTRA76" + }, + { + "name": "EXTRA77" + }, + { + "name": "EXTRA78" + }, + { + "name": "EXTRA79" + }, + { + "name": "EXTRA80" + }, + { + "name": "EXTRA81" + }, + { + "name": "EXTRA82" + }, + { + "name": "EXTRA83" + }, + { + "name": "EXTRA84" + }, + { + "name": "EXTRA85" + }, + { + "name": "EXTRA86" + }, + { + "name": "EXTRA87" + }, + { + "name": "EXTRA88" + }, + { + "name": "EXTRA89" + }, + { + "name": "EXTRA90" + }, + { + "name": "EXTRA91" + }, + { + "name": "EXTRA92" + }, + { + "name": "EXTRA93" + }, + { + "name": "EXTRA94" + }, + { + "name": "EXTRA95" + }, + { + "name": "EXTRA96" + }, + { + "name": "EXTRA97" + }, + { + "name": "EXTRA98" + }, + { + "name": "EXTRA99" + }, + { + "name": "EXTRA100" + }, + { + "name": "EXTRA101" + }, + { + "name": "EXTRA102" + }, + { + "name": "EXTRA103" + }, + { + "name": "EXTRA104" + }, + { + "name": "EXTRA105" + }, + { + "name": "EXTRA106" + }, + { + "name": "EXTRA107" + }, + { + "name": "EXTRA108" + }, + { + "name": "EXTRA109" + }, + { + "name": "EXTRA110" + }, + { + "name": "EXTRA111" + }, + { + "name": "EXTRA112" + }, + { + "name": "EXTRA113" + }, + { + "name": "EXTRA114" + }, + { + "name": "EXTRA115" + }, + { + "name": "EXTRA116" + }, + { + "name": "EXTRA117" + }, + { + "name": "EXTRA118" + }, + { + "name": "EXTRA119" + }, + { + "name": "EXTRA120" + }, + { + "name": "EXTRA121" + }, + { + "name": "EXTRA122" + }, + { + "name": "EXTRA123" + }, + { + "name": "EXTRA124" + }, + { + "name": "EXTRA125" + }, + { + "name": "EXTRA126" + }, + { + "name": "EXTRA127" + }, + { + "name": "EXTRA128" + }, + { + "name": "EXTRA129" + }, + { + "name": "EXTRA130" + }, + { + "name": "EXTRA131" + }, + { + "name": "EXTRA132" + }, + { + "name": "EXTRA133" + }, + { + "name": "EXTRA134" + }, + { + "name": "EXTRA135" + }, + { + "name": "EXTRA136" + }, + { + "name": "EXTRA137" + }, + { + "name": "EXTRA138" + }, + { + "name": "EXTRA139" + }, + { + "name": "EXTRA140" + }, + { + "name": "EXTRA141" + }, + { + "name": "EXTRA142" + }, + { + "name": "EXTRA143" + }, + { + "name": "EXTRA144" + }, + { + "name": "EXTRA145" + }, + { + "name": "EXTRA146" + }, + { + "name": "EXTRA147" + }, + { + "name": "EXTRA148" + }, + { + "name": "EXTRA149" + }, + { + "name": "EXTRA150" + }, + { + "name": "EXTRA151" + }, + { + "name": "EXTRA152" + }, + { + "name": "EXTRA153" + }, + { + "name": "EXTRA154" + }, + { + "name": "EXTRA155" + }, + { + "name": "EXTRA156" + }, + { + "name": "EXTRA157" + }, + { + "name": "EXTRA158" + }, + { + "name": "EXTRA159" + }, + { + "name": "EXTRA160" + }, + { + "name": "EXTRA161" + }, + { + "name": "EXTRA162" + }, + { + "name": "EXTRA163" + }, + { + "name": "EXTRA164" + }, + { + "name": "EXTRA165" + }, + { + "name": "EXTRA166" + }, + { + "name": "EXTRA167" + }, + { + "name": "EXTRA168" + }, + { + "name": "EXTRA169" + }, + { + "name": "EXTRA170" + }, + { + "name": "EXTRA171" + }, + { + "name": "EXTRA172" + }, + { + "name": "EXTRA173" + }, + { + "name": "EXTRA174" + }, + { + "name": "EXTRA175" + }, + { + "name": "EXTRA176" + }, + { + "name": "EXTRA177" + }, + { + "name": "EXTRA178" + }, + { + "name": "EXTRA179" + }, + { + "name": "EXTRA180" + }, + { + "name": "EXTRA181" + }, + { + "name": "EXTRA182" + }, + { + "name": "EXTRA183" + }, + { + "name": "EXTRA184" + }, + { + "name": "EXTRA185" + }, + { + "name": "EXTRA186" + }, + { + "name": "EXTRA187" + }, + { + "name": "EXTRA188" + }, + { + "name": "EXTRA189" + }, + { + "name": "EXTRA190" + }, + { + "name": "EXTRA191" + }, + { + "name": "EXTRA192" + }, + { + "name": "EXTRA193" + }, + { + "name": "EXTRA194" + }, + { + "name": "EXTRA195" + }, + { + "name": "EXTRA196" + }, + { + "name": "EXTRA197" + }, + { + "name": "EXTRA198" + }, + { + "name": "EXTRA199" + }, + { + "name": "EXTRA200" + }, + { + "name": "EXTRA201" + }, + { + "name": "EXTRA202" + }, + { + "name": "EXTRA203" + }, + { + "name": "EXTRA204" + }, + { + "name": "EXTRA205" + }, + { + "name": "EXTRA206" + }, + { + "name": "EXTRA207" + }, + { + "name": "EXTRA208" + }, + { + "name": "EXTRA209" + }, + { + "name": "EXTRA210" + }, + { + "name": "EXTRA211" + }, + { + "name": "EXTRA212" + }, + { + "name": "EXTRA213" + }, + { + "name": "EXTRA214" + }, + { + "name": "EXTRA215" + }, + { + "name": "EXTRA216" + }, + { + "name": "EXTRA217" + }, + { + "name": "EXTRA218" + }, + { + "name": "EXTRA219" + }, + { + "name": "EXTRA220" + }, + { + "name": "EXTRA221" + }, + { + "name": "EXTRA222" + }, + { + "name": "EXTRA223" + }, + { + "name": "EXTRA224" + }, + { + "name": "EXTRA225" + }, + { + "name": "EXTRA226" + }, + { + "name": "EXTRA227" + }, + { + "name": "EXTRA228" + }, + { + "name": "EXTRA229" + }, + { + "name": "EXTRA230" + }, + { + "name": "EXTRA231" + }, + { + "name": "EXTRA232" + }, + { + "name": "EXTRA233" + }, + { + "name": "EXTRA234" + }, + { + "name": "EXTRA235" + }, + { + "name": "EXTRA236" + }, + { + "name": "EXTRA237" + }, + { + "name": "EXTRA238" + }, + { + "name": "EXTRA239" + }, + { + "name": "EXTRA240" + }, + { + "name": "EXTRA241" + }, + { + "name": "EXTRA242" + }, + { + "name": "EXTRA243" + }, + { + "name": "EXTRA244" + }, + { + "name": "EXTRA245" + }, + { + "name": "EXTRA246" + }, + { + "name": "EXTRA247" + }, + { + "name": "EXTRA248" + }, + { + "name": "EXTRA249" + }, + { + "name": "EXTRA250" + }, + { + "name": "EXTRA251" + }, + { + "name": "EXTRA252" + }, + { + "name": "EXTRA253" + }, + { + "name": "EXTRA254" + }, + { + "name": "EXTRA255" + } + ], + "target_commands": [ + "Reserved_0", + "Reserved_1", + "Reserved_2", + "Reserved_3", + "Reserved_4", + "Reserved_5", + "Reserved_6", + "Reserved_7", + "Reserved_8", + "Reserved_9", + "Reserved_10", + "Reserved_11", + "Reserved_12", + "Reserved_13", + "Reserved_14", + "Reserved_15", + "BasicInfo", + "TriggerStatus", + "Pause", + "Resume", + "StepInto", + "StepOver", + "StepOut", + "ListBreak", + "AddBreak", + "DelBreak", + "GetVar", + "PutVar", + "GetCallStack", + "GetLocals", + "Eval", + "Detach", + "DumpHeap", + "GetBytecode", + "AppRequest", + "GetHeapObjInfo", + "GetObjPropDesc", + "GetObjPropDescRange" + ], + "error_codes": [ + "Unknown", + "UnsupportedCommand", + "TooMany", + "NotFound", + "ApplicationError" + ], + "class_names": [ + "unused", + "Arguments", + "Array", + "Boolean", + "Date", + "Error", + "Function", + "JSON", + "Math", + "Number", + "Object", + "RegExp", + "String", + "global", + "ObjEnv", + "DecEnv", + "Buffer", + "Pointer", + "Thread", + "ArrayBuffer", + "DataView", + "Int8Array", + "Uint8Array", + "Uint8ClampedArray", + "Int16Array", + "Uint16Array", + "Int32Array", + "Uint32Array", + "Float32Array", + "Float64Array" + ] +} diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debug_proxy.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debug_proxy.js new file mode 100644 index 000000000..10ba6145d --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debug_proxy.js @@ -0,0 +1,1029 @@ +/* + * JSON debug proxy written in DukLuv + * + * This single file JSON debug proxy implementation is an alternative to the + * Node.js-based proxy in duk_debug.js. DukLuv is a much smaller dependency + * than Node.js so embedding DukLuv in a debug client is easier. + */ + +'use strict'; + +// XXX: Code assumes uv.write() will write fully. This is not necessarily +// true; should add support for partial writes (or at least failing when +// a partial write occurs). + +var log = new Duktape.Logger('Proxy'); // default logger +//log.l = 0; // enable debug and trace logging + +/* + * Config + */ + +var serverHost = '0.0.0.0'; +var serverPort = 9093; +var targetHost = '127.0.0.1'; +var targetPort = 9091; +var singleConnection = false; +var readableNumberValue = false; +var lenientJsonParse = false; +var jxParse = false; +var metadataFile = null; +var metadata = {}; +var TORTURE = false; // for manual testing of binary/json parsing robustness + +/* + * Detect missing 'var' declarations + */ + +// Prevent new bindings on global object. This detects missing 'var' +// declarations, e.g. "x = 123;" in a function without declaring it. +var global = new Function('return this;')(); +log.debug('Preventing extensions on global object'); +log.debug('Global is extensible:', Object.isExtensible(global)); +Object.preventExtensions(global); +log.debug('Global is extensible:', Object.isExtensible(global)); + +/* + * Misc helpers + */ + +function plainBufferCopy(typedarray) { + // This is still pretty awkward in Duktape 1.4.x. + // Argument may be a "slice" and we want a copy of the slice + // (not the full underlying buffer). + + var u8 = new Uint8Array(typedarray.length); + u8.set(typedarray); // make a copy, ensuring there's no slice offset + return Duktape.Buffer(u8); // get underlying plain buffer +} + +function isObject(x) { + // Note that typeof null === 'object'. + return (typeof x === 'object' && x !== null); +} + +function readFully(filename, cb) { + uv.fs_open(metadataFile, 'r', 0, function (handle, err) { + var fileOff = 0; + var data = new Uint8Array(256); + var dataOff = 0; + + if (err) { + return cb(null, err); + } + function readCb(buf, err) { + var res; + var newData; + + log.debug('Read callback:', buf.length, err); + if (err) { + uv.fs_close(handle); + return cb(null, err); + } + if (buf.length == 0) { + uv.fs_close(handle); + res = new Uint8Array(dataOff); + res.set(data.subarray(0, dataOff)); + res = Duktape.Buffer(res); // plain buffer + log.debug('Read', res.length, 'bytes from', filename); + return cb(res, null); + } + while (data.length - dataOff < buf.length) { + log.debug('Resize file read buffer:', data.length, '->', data.length * 2); + newData = new Uint8Array(data.length * 2); + newData.set(data); + data = newData; + } + data.set(new Uint8Array(buf), dataOff); + dataOff += buf.length; + fileOff += buf.length; + uv.fs_read(handle, 4096, fileOff, readCb); + } + uv.fs_read(handle, 4096, fileOff, readCb); + }); +} + +/* + * JSON proxy server + * + * Accepts an incoming JSON proxy client and connects to a debug target, + * tying the two connections together. Supports both a single connection + * and a persistent mode. + */ + +function JsonProxyServer(host, port) { + this.name = 'JsonProxyServer'; + this.handle = uv.new_tcp(); + uv.tcp_bind(this.handle, host, port); + uv.listen(this.handle, 128, this.onConnection.bind(this)); +} + +JsonProxyServer.prototype.onConnection = function onConnection(err) { + if (err) { + log.error('JSON proxy onConnection error:', err); + return; + } + log.info('JSON proxy client connected'); // XXX: it'd be nice to log remote peer host:port + + var jsonSock = new JsonConnHandler(this); + var targSock = new TargetConnHandler(this); + jsonSock.targetHandler = targSock; + targSock.jsonHandler = jsonSock; + uv.accept(this.handle, jsonSock.handle); + + log.info('Connecting to debug target at', targetHost + ':' + targetPort); + jsonSock.writeJson({ notify: '_TargetConnecting', args: [ targetHost, targetPort ] }); + uv.tcp_connect(targSock.handle, targetHost, targetPort, targSock.onConnect.bind(targSock)); + + if (singleConnection) { + log.info('Single connection mode, stop listening for more connections'); + uv.shutdown(this.handle); + uv.read_stop(this.handle); // unnecessary but just in case + uv.close(this.handle); + this.handle = null; + } +}; + +JsonProxyServer.prototype.onProxyClientDisconnected = function onProxyClientDisconnected() { + // When this is invoked the proxy connection and the target connection + // have both been closed. + if (singleConnection) { + log.info('Proxy connection finished (single connection mode: we should be exiting now)'); + } else { + log.info('Proxy connection finished (persistent mode: wait for more connections)'); + } +}; + +/* + * JSON connection handler + */ + +function JsonConnHandler(server) { + var i, n; + + this.name = 'JsonConnHandler'; + this.server = server; + this.handle = uv.new_tcp(); + this.incoming = new Uint8Array(4096); + this.incomingOffset = 0; + this.targetHandler = null; + + this.commandNumberLookup = {}; + if (metadata && metadata.target_commands) { + for (i = 0, n = metadata.target_commands.length; i < n; i++) { + this.commandNumberLookup[metadata.target_commands[i]] = i; + } + } +} + +JsonConnHandler.prototype.finish = function finish(msg) { + var args; + + if (!this.handle) { + log.info('JsonConnHandler already disconnected, ignore finish()'); + return; + } + log.info('JsonConnHandler finished:', msg); + try { + args = msg ? [ msg ] : void 0; + this.writeJson({ notify: '_Disconnecting', args: args }); + } catch (e) { + log.info('Failed to write _Disconnecting notify, ignoring:', e); + } + uv.shutdown(this.handle); + uv.read_stop(this.handle); + uv.close(this.handle); + this.handle = null; + + this.targetHandler.finish(msg); // disconnect target too (if not already disconnected) + + this.server.onProxyClientDisconnected(); +}; + +JsonConnHandler.prototype.onRead = function onRead(err, data) { + var newIncoming; + var msg; + var errmsg; + var tmpBuf; + + log.trace('Received data from JSON socket, err:', err, 'data length:', data ? data.length : 'null'); + + if (err) { + errmsg = 'Error reading data from JSON debug client: ' + err; + this.finish(errmsg); + return; + } + if (data) { + // Feed the data one byte at a time when torture testing. + if (TORTURE && data.length > 1) { + for (var i = 0; i < data.length; i++) { + tmpBuf = Duktape.Buffer(1); + tmpBuf[0] = data[i]; + this.onRead(null, tmpBuf); + } + return; + } + + // Receive data into 'incoming', resizing as necessary. + while (data.length > this.incoming.length - this.incomingOffset) { + newIncoming = new Uint8Array(this.incoming.length * 1.3 + 16); + newIncoming.set(this.incoming); + this.incoming = newIncoming; + log.debug('Resize incoming JSON buffer to ' + this.incoming.length); + } + this.incoming.set(new Uint8Array(data), this.incomingOffset); + this.incomingOffset += data.length; + + // Trial parse JSON message(s). + while (true) { + msg = this.trialParseJsonMessage(); + if (!msg) { + break; + } + try { + this.dispatchJsonMessage(msg); + } catch (e) { + errmsg = 'JSON message dispatch failed: ' + e; + this.writeJson({ notify: '_Error', args: [ errmsg ] }); + if (lenientJsonParse) { + log.warn('JSON message dispatch failed (lenient mode, ignoring):', e); + } else { + log.warn('JSON message dispatch failed (dropping connection):', e); + this.finish(errmsg); + } + } + } + } else { + this.finish('JSON proxy client disconnected'); + } +}; + +JsonConnHandler.prototype.writeJson = function writeJson(msg) { + log.info('PROXY --> CLIENT:', JSON.stringify(msg)); + if (this.handle) { + uv.write(this.handle, JSON.stringify(msg) + '\n'); + } +}; + +JsonConnHandler.prototype.handleDebugMessage = function handleDebugMessage(dvalues) { + var msg = {}; + var idx = 0; + var cmd; + + if (dvalues.length <= 0) { + throw new Error('invalid dvalues list: length <= 0'); + } + var x = dvalues[idx++]; + if (!isObject(x)) { + throw new Error('invalid initial dvalue: ' + Duktape.enc('jx', dvalues)); + } + if (x.type === 'req') { + cmd = dvalues[idx++]; + if (typeof cmd !== 'number') { + throw new Error('invalid command: ' + Duktape.enc('jx', cmd)); + } + msg.request = this.determineCommandName(cmd) || true; + msg.command = cmd; + } else if (x.type === 'rep') { + msg.reply = true; + } else if (x.type === 'err') { + msg.error = true; + } else if (x.type === 'nfy') { + cmd = dvalues[idx++]; + if (typeof cmd !== 'number') { + throw new Error('invalid command: ' + Duktape.enc('jx', cmd)); + } + msg.notify = this.determineCommandName(cmd) || true; + msg.command = cmd; + } else { + throw new Error('invalid initial dvalue: ' + Duktape.enc('jx', dvalues)); + } + + for (; idx < dvalues.length - 1; idx++) { + if (!msg.args) { + msg.args = []; + } + msg.args.push(dvalues[idx]); + } + + if (!isObject(dvalues[idx]) || dvalues[idx].type !== 'eom') { + throw new Error('invalid final dvalue: ' + Duktape.enc('jx', dvalues)); + } + + this.writeJson(msg); +}; + +JsonConnHandler.prototype.determineCommandName = function determineCommandName(cmd) { + if (!(metadata && metadata.client_commands)) { + return; + } + return metadata.client_commands[cmd]; +}; + +JsonConnHandler.prototype.trialParseJsonMessage = function trialParseJsonMessage() { + var buf = this.incoming; + var avail = this.incomingOffset; + var i; + var msg, str, errmsg; + + for (i = 0; i < avail; i++) { + if (buf[i] == 0x0a) { + str = String(plainBufferCopy(buf.subarray(0, i))); + try { + if (jxParse) { + msg = Duktape.dec('jx', str); + } else { + msg = JSON.parse(str); + } + } catch (e) { + // In lenient mode if JSON parse fails just send back an _Error + // and ignore the line (useful for initial development). + // + // In non-lenient mode drop the connection here; if the failed line + // was a request the client is expecting a reply/error message back + // (otherwise it may go out of sync) but we can't send a synthetic + // one (as we can't parse the request). + errmsg = 'JSON parse failed for: ' + JSON.stringify(str) + ': ' + e; + this.writeJson({ notify: '_Error', args: [ errmsg ] }); + if (lenientJsonParse) { + log.warn('JSON parse failed (lenient mode, ignoring):', e); + } else { + log.warn('JSON parse failed (dropping connection):', e); + this.finish(errmsg); + } + } + + this.incoming.set(this.incoming.subarray(i + 1)); + this.incomingOffset -= i + 1; + return msg; + } + } +}; + +JsonConnHandler.prototype.dispatchJsonMessage = function dispatchJsonMessage(msg) { + var cmd; + var dvalues = []; + var i, n; + + log.info('PROXY <-- CLIENT:', JSON.stringify(msg)); + + // Parse message type, determine initial marker for binary message. + if (msg.request) { + cmd = this.determineCommandNumber(msg.request, msg.command); + dvalues.push(new Uint8Array([ 0x01 ])); + dvalues.push(this.encodeJsonDvalue(cmd)); + } else if (msg.reply) { + dvalues.push(new Uint8Array([ 0x02 ])); + } else if (msg.notify) { + cmd = this.determineCommandNumber(msg.notify, msg.command); + dvalues.push(new Uint8Array([ 0x04 ])); + dvalues.push(this.encodeJsonDvalue(cmd)); + } else if (msg.error) { + dvalues.push(new Uint8Array([ 0x03 ])); + } else { + throw new Error('invalid input JSON message: ' + JSON.stringify(msg)); + } + + // Encode arguments into dvalues. + for (i = 0, n = (msg.args ? msg.args.length : 0); i < n; i++) { + dvalues.push(this.encodeJsonDvalue(msg.args[i])); + } + + // Add an EOM, and write out the dvalues to the debug target. + dvalues.push(new Uint8Array([ 0x00 ])); + for (i = 0, n = dvalues.length; i < n; i++) { + this.targetHandler.writeBinary(dvalues[i]); + } +}; + +JsonConnHandler.prototype.determineCommandNumber = function determineCommandNumber(name, val) { + var res; + + if (typeof name === 'string') { + res = this.commandNumberLookup[name]; + if (!res) { + log.info('Unknown command name: ' + name + ', command number: ' + val); + } + } else if (typeof name === 'number') { + res = name; + } else if (name !== true) { + throw new Error('invalid command name (must be string, number, or "true"): ' + name); + } + if (typeof res === 'undefined' && typeof val === 'undefined') { + throw new Error('cannot determine command number from name: ' + name); + } + if (typeof val !== 'number' && typeof val !== 'undefined') { + throw new Error('invalid command number: ' + val); + } + res = res || val; + return res; +}; + +JsonConnHandler.prototype.writeDebugStringToBuffer = function writeDebugStringToBuffer(v, buf, off) { + var i, n; + + for (i = 0, n = v.length; i < n; i++) { + buf[off + i] = v.charCodeAt(i) & 0xff; // truncate higher bits + } +}; + +JsonConnHandler.prototype.encodeJsonDvalue = function encodeJsonDvalue(v) { + var buf, dec, len, dv; + + if (isObject(v)) { + if (v.type === 'eom') { + return new Uint8Array([ 0x00 ]); + } else if (v.type === 'req') { + return new Uint8Array([ 0x01 ]); + } else if (v.type === 'rep') { + return new Uint8Array([ 0x02 ]); + } else if (v.type === 'err') { + return new Uint8Array([ 0x03 ]); + } else if (v.type === 'nfy') { + return new Uint8Array([ 0x04 ]); + } else if (v.type === 'unused') { + return new Uint8Array([ 0x15 ]); + } else if (v.type === 'undefined') { + return new Uint8Array([ 0x16 ]); + } else if (v.type === 'number') { + dec = Duktape.dec('hex', v.data); + len = dec.length; + if (len !== 8) { + throw new TypeError('value cannot be converted to dvalue: ' + JSON.stringify(v)); + } + buf = new Uint8Array(1 + len); + buf[0] = 0x1a; + buf.set(new Uint8Array(dec), 1); + return buf; + } else if (v.type === 'buffer') { + dec = Duktape.dec('hex', v.data); + len = dec.length; + if (len <= 0xffff) { + buf = new Uint8Array(3 + len); + buf[0] = 0x14; + buf[1] = (len >> 8) & 0xff; + buf[2] = (len >> 0) & 0xff; + buf.set(new Uint8Arrau(dec), 3); + return buf; + } else { + buf = new Uint8Array(5 + len); + buf[0] = 0x13; + buf[1] = (len >> 24) & 0xff; + buf[2] = (len >> 16) & 0xff; + buf[3] = (len >> 8) & 0xff; + buf[4] = (len >> 0) & 0xff; + buf.set(new Uint8Array(dec), 5); + return buf; + } + } else if (v.type === 'object') { + dec = Duktape.dec('hex', v.pointer); + len = dec.length; + buf = new Uint8Array(3 + len); + buf[0] = 0x1b; + buf[1] = v.class; + buf[2] = len; + buf.set(new Uint8Array(dec), 3); + return buf; + } else if (v.type === 'pointer') { + dec = Duktape.dec('hex', v.pointer); + len = dec.length; + buf = new Uint8Array(2 + len); + buf[0] = 0x1c; + buf[1] = len; + buf.set(new Uint8Array(dec), 2); + return buf; + } else if (v.type === 'lightfunc') { + dec = Duktape.dec('hex', v.pointer); + len = dec.length; + buf = new Uint8Array(4 + len); + buf[0] = 0x1d; + buf[1] = (v.flags >> 8) & 0xff; + buf[2] = v.flags & 0xff; + buf[3] = len; + buf.set(new Uint8Array(dec), 4); + return buf; + } else if (v.type === 'heapptr') { + dec = Duktape.dec('hex', v.pointer); + len = dec.length; + buf = new Uint8Array(2 + len); + buf[0] = 0x1e; + buf[1] = len; + buf.set(new Uint8Array(dec), 2); + return buf; + } + } else if (v === null) { + return new Uint8Array([ 0x17 ]); + } else if (typeof v === 'boolean') { + return new Uint8Array([ v ? 0x18 : 0x19 ]); + } else if (typeof v === 'number') { + if (Math.floor(v) === v && /* whole */ + (v !== 0 || 1 / v > 0) && /* not negative zero */ + v >= -0x80000000 && v <= 0x7fffffff) { + // Represented signed 32-bit integers as plain integers. + // Debugger code expects this for all fields that are not + // duk_tval representations (e.g. command numbers and such). + if (v >= 0x00 && v <= 0x3f) { + return new Uint8Array([ 0x80 + v ]); + } else if (v >= 0x0000 && v <= 0x3fff) { + return new Uint8Array([ 0xc0 + (v >> 8), v & 0xff ]); + } else if (v >= -0x80000000 && v <= 0x7fffffff) { + return new Uint8Array([ 0x10, + (v >> 24) & 0xff, + (v >> 16) & 0xff, + (v >> 8) & 0xff, + (v >> 0) & 0xff ]); + } else { + throw new Error('internal error when encoding integer to dvalue: ' + v); + } + } else { + // Represent non-integers as IEEE double dvalues. + buf = new Uint8Array(1 + 8); + buf[0] = 0x1a; + new DataView(buf).setFloat64(1, v, false); + return buf; + } + } else if (typeof v === 'string') { + if (v.length < 0 || v.length > 0xffffffff) { + // Not possible in practice. + throw new TypeError('cannot convert to dvalue, invalid string length: ' + v.length); + } + if (v.length <= 0x1f) { + buf = new Uint8Array(1 + v.length); + buf[0] = 0x60 + v.length; + this.writeDebugStringToBuffer(v, buf, 1); + return buf; + } else if (v.length <= 0xffff) { + buf = new Uint8Array(3 + v.length); + buf[0] = 0x12; + buf[1] = (v.length >> 8) & 0xff; + buf[2] = (v.length >> 0) & 0xff; + this.writeDebugStringToBuffer(v, buf, 3); + return buf; + } else { + buf = new Uint8Array(5 + v.length); + buf[0] = 0x11; + buf[1] = (v.length >> 24) & 0xff; + buf[2] = (v.length >> 16) & 0xff; + buf[3] = (v.length >> 8) & 0xff; + buf[4] = (v.length >> 0) & 0xff; + this.writeDebugStringToBuffer(v, buf, 5); + return buf; + } + } + + throw new TypeError('value cannot be converted to dvalue: ' + JSON.stringify(v)); +}; + +/* + * Target binary connection handler + */ + +function TargetConnHandler(server) { + this.name = 'TargetConnHandler'; + this.server = server; + this.handle = uv.new_tcp(); + this.jsonHandler = null; + this.incoming = new Uint8Array(4096); + this.incomingOffset = 0; + this.dvalues = []; +} + +TargetConnHandler.prototype.finish = function finish(msg) { + if (!this.handle) { + log.info('TargetConnHandler already disconnected, ignore finish()'); + return; + } + log.info('TargetConnHandler finished:', msg); + + this.jsonHandler.writeJson({ notify: '_TargetDisconnected' }); + + // XXX: write a notify to target? + + uv.shutdown(this.handle); + uv.read_stop(this.handle); + uv.close(this.handle); + this.handle = null; + + this.jsonHandler.finish(msg); // disconnect JSON client too (if not already disconnected) +}; + +TargetConnHandler.prototype.onConnect = function onConnect(err) { + var errmsg; + + if (err) { + errmsg = 'Failed to connect to target: ' + err; + log.warn(errmsg); + this.jsonHandler.writeJson({ notify: '_Error', args: [ String(err) ] }); + this.finish(errmsg); + return; + } + + // Once we're connected to the target, start read both binary and JSON + // input. We don't want to read JSON input before this so that we can + // always translate incoming messages to dvalues and write them out + // without queueing. Any pending JSON messages will be queued by the + // OS instead. + + log.info('Connected to debug target at', targetHost + ':' + targetPort); + uv.read_start(this.jsonHandler.handle, this.jsonHandler.onRead.bind(this.jsonHandler)); + uv.read_start(this.handle, this.onRead.bind(this)); +}; + +TargetConnHandler.prototype.writeBinary = function writeBinary(buf) { + var plain = plainBufferCopy(buf); + log.info('PROXY --> TARGET:', Duktape.enc('jx', plain)); + if (this.handle) { + uv.write(this.handle, plain); + } +}; + +TargetConnHandler.prototype.onRead = function onRead(err, data) { + var res; + var errmsg; + var tmpBuf; + var newIncoming; + + log.trace('Received data from target socket, err:', err, 'data length:', data ? data.length : 'null'); + + if (err) { + errmsg = 'Error reading data from debug target: ' + err; + this.finish(errmsg); + return; + } + + if (data) { + // Feed the data one byte at a time when torture testing. + if (TORTURE && data.length > 1) { + for (var i = 0; i < data.length; i++) { + tmpBuf = Duktape.Buffer(1); + tmpBuf[0] = data[i]; + this.onRead(null, tmpBuf); + } + return; + } + + // Receive data into 'incoming', resizing as necessary. + while (data.length > this.incoming.length - this.incomingOffset) { + newIncoming = new Uint8Array(this.incoming.length * 1.3 + 16); + newIncoming.set(this.incoming); + this.incoming = newIncoming; + log.debug('Resize incoming binary buffer to ' + this.incoming.length); + } + this.incoming.set(new Uint8Array(data), this.incomingOffset); + this.incomingOffset += data.length; + + // Trial parse handshake unless done. + if (!this.handshake) { + this.trialParseHandshake(); + } + + // Trial parse dvalue(s) and debug messages. + if (this.handshake) { + for (;;) { + res = this.trialParseDvalue(); + if (!res) { + break; + } + log.trace('Got dvalue:', Duktape.enc('jx', res.dvalue)); + this.dvalues.push(res.dvalue); + if (isObject(res.dvalue) && res.dvalue.type === 'eom') { + try { + this.jsonHandler.handleDebugMessage(this.dvalues); + this.dvalues = []; + } catch (e) { + errmsg = 'JSON message handling failed: ' + e; + this.jsonHandler.writeJson({ notify: '_Error', args: [ errmsg ] }); + if (lenientJsonParse) { + log.warn('JSON message handling failed (lenient mode, ignoring):', e); + } else { + log.warn('JSON message handling failed (dropping connection):', e); + this.finish(errmsg); + } + } + } + } + } + } else { + log.info('Target disconnected'); + this.finish('Target disconnected'); + } +}; + +TargetConnHandler.prototype.trialParseHandshake = function trialParseHandshake() { + var buf = this.incoming; + var avail = this.incomingOffset; + var i; + var msg; + var m; + var protocolVersion; + + for (i = 0; i < avail; i++) { + if (buf[i] == 0x0a) { + msg = String(plainBufferCopy(buf.subarray(0, i))); + this.incoming.set(this.incoming.subarray(i + 1)); + this.incomingOffset -= i + 1; + + // Generic handshake format: only relies on initial version field. + m = /^(\d+) (.*)$/.exec(msg) || {}; + protocolVersion = +m[1]; + this.handshake = { + line: msg, + protocolVersion: protocolVersion, + text: m[2] + }; + + // More detailed v1 handshake line. + if (protocolVersion === 1) { + m = /^(\d+) (\d+) (.*?) (.*?) (.*)$/.exec(msg) || {}; + this.handshake.dukVersion = m[1]; + this.handshake.dukGitDescribe = m[2]; + this.handshake.targetString = m[3]; + } + + this.jsonHandler.writeJson({ notify: '_TargetConnected', args: [ msg ] }); + + log.info('Target handshake: ' + JSON.stringify(this.handshake)); + return; + } + } +}; + +TargetConnHandler.prototype.bufferToDebugString = function bufferToDebugString(buf) { + return String.fromCharCode.apply(null, buf); +}; + +TargetConnHandler.prototype.trialParseDvalue = function trialParseDvalue() { + var _this = this; + var buf = this.incoming; + var avail = this.incomingOffset; + var v; + var gotValue = false; // explicit flag for e.g. v === undefined + var dv = new DataView(buf); + var tmp; + var x; + var len; + + function consume(n) { + log.info('PROXY <-- TARGET:', Duktape.enc('jx', _this.incoming.subarray(0, n))); + _this.incoming.set(_this.incoming.subarray(n)); + _this.incomingOffset -= n; + } + + x = buf[0]; + if (avail <= 0) { + ; + } else if (x >= 0xc0) { + // 0xc0...0xff: integers 0-16383 + if (avail >= 2) { + v = ((x - 0xc0) << 8) + buf[1]; + consume(2); + } + } else if (x >= 0x80) { + // 0x80...0xbf: integers 0-63 + v = x - 0x80; + consume(1); + } else if (x >= 0x60) { + // 0x60...0x7f: strings with length 0-31 + len = x - 0x60; + if (avail >= 1 + len) { + v = new Uint8Array(len); + v.set(buf.subarray(1, 1 + len)); + v = this.bufferToDebugString(v); + consume(1 + len); + } + } else { + switch (x) { + case 0x00: consume(1); v = { type: 'eom' }; break; + case 0x01: consume(1); v = { type: 'req' }; break; + case 0x02: consume(1); v = { type: 'rep' }; break; + case 0x03: consume(1); v = { type: 'err' }; break; + case 0x04: consume(1); v = { type: 'nfy' }; break; + case 0x10: // 4-byte signed integer + if (avail >= 5) { + v = dv.getInt32(1, false); + consume(5); + } + break; + case 0x11: // 4-byte string + if (avail >= 5) { + len = dv.getUint32(1, false); + if (avail >= 5 + len) { + v = new Uint8Array(len); + v.set(buf.subarray(5, 5 + len)); + v = this.bufferToDebugString(v); + consume(5 + len); + } + } + break; + case 0x12: // 2-byte string + if (avail >= 3) { + len = dv.getUint16(1, false); + if (avail >= 3 + len) { + v = new Uint8Array(len); + v.set(buf.subarray(3, 3 + len)); + v = this.bufferToDebugString(v); + consume(3 + len); + } + } + break; + case 0x13: // 4-byte buffer + if (avail >= 5) { + len = dv.getUint32(1, false); + if (avail >= 5 + len) { + v = new Uint8Array(len); + v.set(buf.subarray(5, 5 + len)); + v = { type: 'buffer', data: Duktape.enc('hex', Duktape.Buffer(v)) }; + consume(5 + len); + } + } + break; + case 0x14: // 2-byte buffer + if (avail >= 3) { + len = dv.getUint16(1, false); + if (avail >= 3 + len) { + v = new Uint8Array(len); + v.set(buf.subarray(3, 3 + len)); + v = { type: 'buffer', data: Duktape.enc('hex', Duktape.Buffer(v)) }; + consume(3 + len); + } + } + break; + case 0x15: // unused/none + v = { type: 'unused' }; + consume(1); + break; + case 0x16: // undefined + v = { type: 'undefined' }; + gotValue = true; // indicate 'v' is actually set + consume(1); + break; + case 0x17: // null + v = null; + gotValue = true; // indicate 'v' is actually set + consume(1); + break; + case 0x18: // true + v = true; + consume(1); + break; + case 0x19: // false + v = false; + consume(1); + break; + case 0x1a: // number (IEEE double), big endian + if (avail >= 9) { + tmp = new Uint8Array(8); + tmp.set(buf.subarray(1, 9)); + v = { type: 'number', data: Duktape.enc('hex', Duktape.Buffer(tmp)) }; + if (readableNumberValue) { + // The value key should not be used programmatically, + // it is just there to make the dumps more readable. + v.value = new DataView(tmp.buffer).getFloat64(0, false); + } + consume(9); + } + break; + case 0x1b: // object + if (avail >= 3) { + len = buf[2]; + if (avail >= 3 + len) { + v = new Uint8Array(len); + v.set(buf.subarray(3, 3 + len)); + v = { type: 'object', 'class': buf[1], pointer: Duktape.enc('hex', Duktape.Buffer(v)) }; + consume(3 + len); + } + } + break; + case 0x1c: // pointer + if (avail >= 2) { + len = buf[1]; + if (avail >= 2 + len) { + v = new Uint8Array(len); + v.set(buf.subarray(2, 2 + len)); + v = { type: 'pointer', pointer: Duktape.enc('hex', Duktape.Buffer(v)) }; + consume(2 + len); + } + } + break; + case 0x1d: // lightfunc + if (avail >= 4) { + len = buf[3]; + if (avail >= 4 + len) { + v = new Uint8Array(len); + v.set(buf.subarray(4, 4 + len)); + v = { type: 'lightfunc', flags: dv.getUint16(1, false), pointer: Duktape.enc('hex', Duktape.Buffer(v)) }; + consume(4 + len); + } + } + break; + case 0x1e: // heapptr + if (avail >= 2) { + len = buf[1]; + if (avail >= 2 + len) { + v = new Uint8Array(len); + v.set(buf.subarray(2, 2 + len)); + v = { type: 'heapptr', pointer: Duktape.enc('hex', Duktape.Buffer(v)) }; + consume(2 + len); + } + } + break; + default: + throw new Error('failed parse initial byte: ' + buf[0]); + } + } + + if (typeof v !== 'undefined' || gotValue) { + return { dvalue: v }; + } +}; + +/* + * Main + */ + +function main() { + var argv = typeof uv.argv === 'function' ? uv.argv() : []; + var i; + for (i = 2; i < argv.length; i++) { // skip dukluv and script name + if (argv[i] == '--help') { + print('Usage: dukluv ' + argv[1] + ' [option]+'); + print(''); + print(' --server-host HOST JSON proxy server listen address'); + print(' --server-port PORT JSON proxy server listen port'); + print(' --target-host HOST Debug target address'); + print(' --target-port PORT Debug target port'); + print(' --metadata FILE Proxy metadata file (usually named duk_debug_meta.json)'); + print(' --log-level LEVEL Set log level, default is 2; 0=trace, 1=debug, 2=info, 3=warn, etc'); + print(' --single Run a single proxy connection and exit (default: persist for multiple connections)'); + print(' --readable-numbers Add a non-programmatic "value" key for IEEE doubles help readability'); + print(' --lenient Ignore (with warning) invalid JSON without dropping connection'); + print(' --jx-parse Parse JSON proxy input with JX, useful when testing manually'); + print(''); + return; // don't register any sockets/timers etc to exit + } else if (argv[i] == '--single') { + singleConnection = true; + continue; + } else if (argv[i] == '--readable-numbers') { + readableNumberValue = true; + continue; + } else if (argv[i] == '--lenient') { + lenientJsonParse = true; + continue; + } else if (argv[i] == '--jx-parse') { + jxParse = true; + continue; + } + if (i >= argv.length - 1) { + throw new Error('missing option value for ' + argv[i]); + } + if (argv[i] == '--server-host') { + serverHost = argv[i + 1]; + i++; + } else if (argv[i] == '--server-port') { + serverPort = Math.floor(+argv[i + 1]); + i++; + } else if (argv[i] == '--target-host') { + targetHost = argv[i + 1]; + i++; + } else if (argv[i] == '--target-port') { + targetPort = Math.floor(+argv[i + 1]); + i++; + } else if (argv[i] == '--metadata') { + metadataFile = argv[i + 1]; + i++; + } else if (argv[i] == '--log-level') { + log.l = Math.floor(+argv[i + 1]); + i++; + } else { + throw new Error('invalid option ' + argv[i]); + } + } + + function runServer() { + var serverSocket = new JsonProxyServer(serverHost, serverPort); + var connMode = singleConnection ? 'single connection mode' : 'persistent connection mode'; + log.info('Listening for incoming JSON debug connection on ' + serverHost + ':' + serverPort + + ', target is ' + targetHost + ':' + targetPort + ', ' + connMode); + } + + if (metadataFile) { + log.info('Read proxy metadata from', metadataFile); + readFully(metadataFile, function (data, err) { + if (err) { + log.error('Failed to load metadata:', err); + throw err; + } + try { + metadata = JSON.parse(String(data)); + } catch (e) { + log.error('Failed to parse JSON metadata from ' + metadataFile + ': ' + e); + throw e; + } + runServer(); + }); + } else { + runServer(); + } +} + +main(); diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debugcommands.yaml b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debugcommands.yaml new file mode 100644 index 000000000..14555c189 --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debugcommands.yaml @@ -0,0 +1,52 @@ +# Debug request/notify command names provided by the debug client. +# These are concretely notify names now. +client_commands: + - Reserved_0 + - Status + - Print + - Alert + - Log + - Throw + - Detaching + - AppNotify + +# Debug request/notify command names provided by the debug target (Duktape). +target_commands: + - Reserved_0 + - Reserved_1 + - Reserved_2 + - Reserved_3 + - Reserved_4 + - Reserved_5 + - Reserved_6 + - Reserved_7 + - Reserved_8 + - Reserved_9 + - Reserved_10 + - Reserved_11 + - Reserved_12 + - Reserved_13 + - Reserved_14 + - Reserved_15 + - BasicInfo + - TriggerStatus + - Pause + - Resume + - StepInto + - StepOver + - StepOut + - ListBreak + - AddBreak + - DelBreak + - GetVar + - PutVar + - GetCallStack + - GetLocals + - Eval + - Detach + - DumpHeap + - GetBytecode + - AppRequest + - GetHeapObjInfo + - GetObjPropDesc + - GetObjPropDescRange diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debugerrors.yaml b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debugerrors.yaml new file mode 100644 index 000000000..500265f7b --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_debugerrors.yaml @@ -0,0 +1,6 @@ +error_codes: + - Unknown + - UnsupportedCommand + - TooMany + - NotFound + - ApplicationError diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/duk_opcodes.yaml b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_opcodes.yaml similarity index 99% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/duk_opcodes.yaml rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_opcodes.yaml index a82ac8cad..67dbefb75 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/duk_opcodes.yaml +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/duk_opcodes.yaml @@ -243,8 +243,6 @@ opcodes: - B_RC flags: - mask: 0x40 - name: fast_return - - mask: 0x80 name: have_retval - name: CALL args: diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/merge_debug_meta.py b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/merge_debug_meta.py new file mode 100644 index 000000000..ba9b38e3d --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/merge_debug_meta.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python2 +# +# Merge debugger YAML metadata files and output a merged JSON metadata file. +# + +import os, sys, json, yaml +import optparse + +if __name__ == '__main__': + parser = optparse.OptionParser() + parser.add_option('--output', dest='output', default=None, help='output JSON filename') + parser.add_option('--class-names', dest='class_names', help='YAML metadata for class names') + parser.add_option('--debug-commands', dest='debug_commands', help='YAML metadata for debug commands') + parser.add_option('--debug-errors', dest='debug_errors', help='YAML metadata for debug protocol error codes') + parser.add_option('--opcodes', dest='opcodes', help='YAML metadata for opcodes') + (opts, args) = parser.parse_args() + + res = {} + def merge(fn): + with open(fn, 'rb') as f: + doc = yaml.load(f) + for k in doc.keys(): + res[k] = doc[k] + + merge(opts.class_names) + merge(opts.debug_commands) + merge(opts.debug_errors) + merge(opts.opcodes) + + with open(opts.output, 'wb') as f: + f.write(json.dumps(res, indent=4) + '\n') + print('Wrote merged debugger metadata to ' + str(opts.output)) diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/package.json b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/package.json similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/package.json rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/package.json diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/static/index.html b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/index.html similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/static/index.html rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/index.html diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/static/style.css b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/style.css similarity index 98% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/static/style.css rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/style.css index ce8d34f60..a1059478f 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/static/style.css +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/style.css @@ -358,9 +358,13 @@ margin: 10px 0 10px 0; } #bytecode-dialog pre { - font: 14pt monospace; + font: 10pt monospace; color: #000000; } +#bytecode-dialog div.highlight { + background: #888888; + color: #ffffff; +} #eval { color: #000000; diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/static/webui.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/webui.js similarity index 89% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/static/webui.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/webui.js index e3e1cc111..d400c6c35 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/debugger/static/webui.js +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/webui.js @@ -23,21 +23,24 @@ var sourceEditedLines = []; // line numbers which have been modified var sourceUpdateInterval = null; // timer for updating source view var sourceFetchXhr = null; // current AJAX request for fetching a source file (if any) var forceButtonUpdate = false; // hack to reset button states +var bytecodeDialogOpen = false; // bytecode dialog active +var bytecodeIdxHighlight = null; // index of currently highlighted line (or null) +var bytecodeIdxInstr = 0; // index to first line of bytecode instructions // Execution state -var prevState = null; // previous execution state ('paused', 'running', etc) -var prevAttached = null; // previous debugger attached state (true, false, null) -var currFileName = null; // current filename being executed -var currFuncName = null; // current function name being executed -var currLine = 0; // current line being executed -var currPc = 0; // current bytecode PC being executed -var currState = 0; // current execution state ('paused', 'running', 'detached', etc) -var currAttached = false; // current debugger attached state (true or false) -var currLocals = []; // current local variables -var currCallstack = []; // current callstack (from top to bottom) -var currBreakpoints = []; // current breakpoints -var startedRunning = 0; // timestamp when last started running (if running) - // (used to grey out the source file if running for long enough) +var prevState = null; // previous execution state ('paused', 'running', etc) +var prevAttached = null; // previous debugger attached state (true, false, null) +var currFileName = null; // current filename being executed +var currFuncName = null; // current function name being executed +var currLine = 0; // current line being executed +var currPc = 0; // current bytecode PC being executed +var currState = 0; // current execution state ('paused', 'running', 'detached', etc) +var currAttached = false; // current debugger attached state (true or false) +var currLocals = []; // current local variables +var currCallstack = []; // current callstack (from top to bottom) +var currBreakpoints = []; // current breakpoints +var startedRunning = 0; // timestamp when last started running (if running) + // (used to grey out the source file if running for long enough) /* * Helpers @@ -99,6 +102,15 @@ function doSourceUpdate() { } } + // Bytecode dialog highlight + if (loadedFileExecuting && bytecodeDialogOpen && bytecodeIdxHighlight !== bytecodeIdxInstr + currPc) { + if (typeof bytecodeIdxHighlight === 'number') { + $('#bytecode-preformatted div')[bytecodeIdxHighlight].classList.remove('highlight'); + } + bytecodeIdxHighlight = bytecodeIdxInstr + currPc; + $('#bytecode-preformatted div')[bytecodeIdxHighlight].classList.add('highlight'); + } + // If no-one requested us to scroll to a specific line, finish. if (loadedLinePending == null) { return; @@ -280,6 +292,11 @@ socket.on('basic-info', function (msg) { }); socket.on('exec-status', function (msg) { + // Not 100% reliable if callstack has several functions of the same name + if (bytecodeDialogOpen && (currFileName != msg.fileName || currFuncName != msg.funcName)) { + socket.emit('get-bytecode', {}); + } + currFileName = msg.fileName; currFuncName = msg.funcName; currLine = msg.line; @@ -455,8 +472,20 @@ socket.on('getvar-result', function (msg) { }); socket.on('bytecode', function (msg) { - $('#bytecode-preformatted').text(msg.preformatted); - $('#bytecode-dialog').dialog('open'); + var elem, div; + var div; + + elem = $('#bytecode-preformatted'); + elem.empty(); + + msg.preformatted.split('\n').forEach(function (line, idx) { + div = $('
'); + div.text(line); + elem.append(div); + }); + + bytecodeIdxHighlight = null; + bytecodeIdxInstr = msg.idxPreformattedInstructions; }); $('#stepinto-button').click(function () { @@ -495,6 +524,12 @@ $('#about-button').click(function () { }); $('#show-bytecode-button').click(function () { + bytecodeDialogOpen = true; + $('#bytecode-dialog').dialog('open'); + + elem = $('#bytecode-preformatted'); + elem.empty().text('Loading bytecode...'); + socket.emit('get-bytecode', {}); }); @@ -702,8 +737,13 @@ $(document).ready(function () { autoOpen: false, hide: 'fade', // puff show: 'fade', // slide, puff - width: 1000, - height: 800 + width: 700, + height: 600, + close: function () { + bytecodeDialogOpen = false; + bytecodeIdxHighlight = null; + bytecodeIdxInstr = 0; + } }); // http://diveintohtml5.info/storage.html diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/duk_build_meta.json b/ceph/src/civetweb/src/third_party/duktape-1.5.2/duk_build_meta.json new file mode 100644 index 000000000..c2e80bb2f --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/duk_build_meta.json @@ -0,0 +1,1349 @@ +{ + "builtin_strings": [ + "Undefined", + "Null", + "Arguments", + "Object", + "Function", + "Array", + "String", + "Boolean", + "Number", + "Date", + "RegExp", + "Error", + "Math", + "JSON", + "", + "ArrayBuffer", + "DataView", + "Int8Array", + "Uint8Array", + "Uint8ClampedArray", + "Int16Array", + "Uint16Array", + "Int32Array", + "Uint32Array", + "Float32Array", + "Float64Array", + "global", + "ObjEnv", + "DecEnv", + "Buffer", + "Pointer", + "Thread", + "eval", + "defineProperty", + "value", + "writable", + "configurable", + "enumerable", + "join", + "toLocaleString", + "valueOf", + "toUTCString", + "toISOString", + "toGMTString", + "source", + "ignoreCase", + "multiline", + "lastIndex", + "(?:)", + "index", + "prototype", + "constructor", + "message", + "boolean", + "number", + "string", + "object", + "undefined", + "NaN", + "Infinity", + "-Infinity", + "-0", + ",", + " ", + "\n ", + "[...]", + "Invalid Date", + "arguments", + "callee", + "caller", + "has", + "get", + "deleteProperty", + "enumerate", + "ownKeys", + "setPrototypeOf", + "__proto__", + "require", + "id", + "exports", + "filename", + "toString", + "toJSON", + "type", + "data", + "length", + "byteLength", + "byteOffset", + "BYTES_PER_ELEMENT", + "set", + "stack", + "pc", + "lineNumber", + "\u00ffTracedata", + "name", + "fileName", + "buffer", + "pointer", + "\u00ffValue", + "\u00ffNext", + "\u00ffBytecode", + "\u00ffFormals", + "\u00ffVarmap", + "\u00ffLexenv", + "\u00ffVarenv", + "\u00ffSource", + "\u00ffPc2line", + "\u00ffArgs", + "\u00ffMap", + "\u00ffFinalizer", + "\u00ffHandler", + "\u00ffCallee", + "\u00ffThread", + "\u00ffRegbase", + "\u00ffTarget", + "\u00ffThis", + "compile", + "input", + "errCreate", + "errThrow", + "modSearch", + "modLoaded", + "env", + "hex", + "base64", + "jx", + "jc", + "resume", + "fmt", + "raw", + "trace", + "debug", + "info", + "warn", + "error", + "fatal", + "n", + "l", + "clog", + "toLogString", + "{\"_undef\":true}", + "{\"_nan\":true}", + "{\"_inf\":true}", + "{\"_ninf\":true}", + "{\"_func\":true}", + "{_func:true}", + "break", + "case", + "catch", + "continue", + "debugger", + "default", + "delete", + "do", + "else", + "finally", + "for", + "function", + "if", + "in", + "instanceof", + "new", + "return", + "switch", + "this", + "throw", + "try", + "typeof", + "var", + "const", + "void", + "while", + "with", + "class", + "enum", + "export", + "extends", + "import", + "super", + "null", + "true", + "false", + "implements", + "interface", + "let", + "package", + "private", + "protected", + "public", + "static", + "yield" + ], + "builtin_strings_base64": [ + "VW5kZWZpbmVk", + "TnVsbA==", + "QXJndW1lbnRz", + "T2JqZWN0", + "RnVuY3Rpb24=", + "QXJyYXk=", + "U3RyaW5n", + "Qm9vbGVhbg==", + "TnVtYmVy", + "RGF0ZQ==", + "UmVnRXhw", + "RXJyb3I=", + "TWF0aA==", + "SlNPTg==", + "", + "QXJyYXlCdWZmZXI=", + "RGF0YVZpZXc=", + "SW50OEFycmF5", + "VWludDhBcnJheQ==", + "VWludDhDbGFtcGVkQXJyYXk=", + "SW50MTZBcnJheQ==", + "VWludDE2QXJyYXk=", + "SW50MzJBcnJheQ==", + "VWludDMyQXJyYXk=", + "RmxvYXQzMkFycmF5", + "RmxvYXQ2NEFycmF5", + "Z2xvYmFs", + "T2JqRW52", + "RGVjRW52", + "QnVmZmVy", + "UG9pbnRlcg==", + "VGhyZWFk", + "ZXZhbA==", + "ZGVmaW5lUHJvcGVydHk=", + "dmFsdWU=", + "d3JpdGFibGU=", + "Y29uZmlndXJhYmxl", + "ZW51bWVyYWJsZQ==", + "am9pbg==", + "dG9Mb2NhbGVTdHJpbmc=", + "dmFsdWVPZg==", + "dG9VVENTdHJpbmc=", + "dG9JU09TdHJpbmc=", + "dG9HTVRTdHJpbmc=", + "c291cmNl", + "aWdub3JlQ2FzZQ==", + "bXVsdGlsaW5l", + "bGFzdEluZGV4", + "KD86KQ==", + "aW5kZXg=", + "cHJvdG90eXBl", + "Y29uc3RydWN0b3I=", + "bWVzc2FnZQ==", + "Ym9vbGVhbg==", + "bnVtYmVy", + "c3RyaW5n", + "b2JqZWN0", + "dW5kZWZpbmVk", + "TmFO", + "SW5maW5pdHk=", + "LUluZmluaXR5", + "LTA=", + "LA==", + "IA==", + "CiAgICA=", + "Wy4uLl0=", + "SW52YWxpZCBEYXRl", + "YXJndW1lbnRz", + "Y2FsbGVl", + "Y2FsbGVy", + "aGFz", + "Z2V0", + "ZGVsZXRlUHJvcGVydHk=", + "ZW51bWVyYXRl", + "b3duS2V5cw==", + "c2V0UHJvdG90eXBlT2Y=", + "X19wcm90b19f", + "cmVxdWlyZQ==", + "aWQ=", + "ZXhwb3J0cw==", + "ZmlsZW5hbWU=", + "dG9TdHJpbmc=", + "dG9KU09O", + "dHlwZQ==", + "ZGF0YQ==", + "bGVuZ3Ro", + "Ynl0ZUxlbmd0aA==", + "Ynl0ZU9mZnNldA==", + "QllURVNfUEVSX0VMRU1FTlQ=", + "c2V0", + "c3RhY2s=", + "cGM=", + "bGluZU51bWJlcg==", + "/1RyYWNlZGF0YQ==", + "bmFtZQ==", + "ZmlsZU5hbWU=", + "YnVmZmVy", + "cG9pbnRlcg==", + "/1ZhbHVl", + "/05leHQ=", + "/0J5dGVjb2Rl", + "/0Zvcm1hbHM=", + "/1Zhcm1hcA==", + "/0xleGVudg==", + "/1ZhcmVudg==", + "/1NvdXJjZQ==", + "/1BjMmxpbmU=", + "/0FyZ3M=", + "/01hcA==", + "/0ZpbmFsaXplcg==", + "/0hhbmRsZXI=", + "/0NhbGxlZQ==", + "/1RocmVhZA==", + "/1JlZ2Jhc2U=", + "/1RhcmdldA==", + "/1RoaXM=", + "Y29tcGlsZQ==", + "aW5wdXQ=", + "ZXJyQ3JlYXRl", + "ZXJyVGhyb3c=", + "bW9kU2VhcmNo", + "bW9kTG9hZGVk", + "ZW52", + "aGV4", + "YmFzZTY0", + "ang=", + "amM=", + "cmVzdW1l", + "Zm10", + "cmF3", + "dHJhY2U=", + "ZGVidWc=", + "aW5mbw==", + "d2Fybg==", + "ZXJyb3I=", + "ZmF0YWw=", + "bg==", + "bA==", + "Y2xvZw==", + "dG9Mb2dTdHJpbmc=", + "eyJfdW5kZWYiOnRydWV9", + "eyJfbmFuIjp0cnVlfQ==", + "eyJfaW5mIjp0cnVlfQ==", + "eyJfbmluZiI6dHJ1ZX0=", + "eyJfZnVuYyI6dHJ1ZX0=", + "e19mdW5jOnRydWV9", + "YnJlYWs=", + "Y2FzZQ==", + "Y2F0Y2g=", + "Y29udGludWU=", + "ZGVidWdnZXI=", + "ZGVmYXVsdA==", + "ZGVsZXRl", + "ZG8=", + "ZWxzZQ==", + "ZmluYWxseQ==", + "Zm9y", + "ZnVuY3Rpb24=", + "aWY=", + "aW4=", + "aW5zdGFuY2VvZg==", + "bmV3", + "cmV0dXJu", + "c3dpdGNo", + "dGhpcw==", + "dGhyb3c=", + "dHJ5", + "dHlwZW9m", + "dmFy", + "Y29uc3Q=", + "dm9pZA==", + "d2hpbGU=", + "d2l0aA==", + "Y2xhc3M=", + "ZW51bQ==", + "ZXhwb3J0", + "ZXh0ZW5kcw==", + "aW1wb3J0", + "c3VwZXI=", + "bnVsbA==", + "dHJ1ZQ==", + "ZmFsc2U=", + "aW1wbGVtZW50cw==", + "aW50ZXJmYWNl", + "bGV0", + "cGFja2FnZQ==", + "cHJpdmF0ZQ==", + "cHJvdGVjdGVk", + "cHVibGlj", + "c3RhdGlj", + "eWllbGQ=" + ], + "builtin_strings_info": [ + { + "base64": "VW5kZWZpbmVk", + "define": "DUK_STRIDX_UC_UNDEFINED", + "plain": "Undefined" + }, + { + "base64": "TnVsbA==", + "define": "DUK_STRIDX_UC_NULL", + "plain": "Null" + }, + { + "base64": "QXJndW1lbnRz", + "define": "DUK_STRIDX_UC_ARGUMENTS", + "plain": "Arguments" + }, + { + "base64": "T2JqZWN0", + "define": "DUK_STRIDX_UC_OBJECT", + "plain": "Object" + }, + { + "base64": "RnVuY3Rpb24=", + "define": "DUK_STRIDX_UC_FUNCTION", + "plain": "Function" + }, + { + "base64": "QXJyYXk=", + "define": "DUK_STRIDX_ARRAY", + "plain": "Array" + }, + { + "base64": "U3RyaW5n", + "define": "DUK_STRIDX_UC_STRING", + "plain": "String" + }, + { + "base64": "Qm9vbGVhbg==", + "define": "DUK_STRIDX_UC_BOOLEAN", + "plain": "Boolean" + }, + { + "base64": "TnVtYmVy", + "define": "DUK_STRIDX_UC_NUMBER", + "plain": "Number" + }, + { + "base64": "RGF0ZQ==", + "define": "DUK_STRIDX_DATE", + "plain": "Date" + }, + { + "base64": "UmVnRXhw", + "define": "DUK_STRIDX_REG_EXP", + "plain": "RegExp" + }, + { + "base64": "RXJyb3I=", + "define": "DUK_STRIDX_UC_ERROR", + "plain": "Error" + }, + { + "base64": "TWF0aA==", + "define": "DUK_STRIDX_MATH", + "plain": "Math" + }, + { + "base64": "SlNPTg==", + "define": "DUK_STRIDX_JSON", + "plain": "JSON" + }, + { + "base64": "", + "define": "DUK_STRIDX_EMPTY_STRING", + "plain": "" + }, + { + "base64": "QXJyYXlCdWZmZXI=", + "define": "DUK_STRIDX_ARRAY_BUFFER", + "plain": "ArrayBuffer" + }, + { + "base64": "RGF0YVZpZXc=", + "define": "DUK_STRIDX_DATA_VIEW", + "plain": "DataView" + }, + { + "base64": "SW50OEFycmF5", + "define": "DUK_STRIDX_INT8_ARRAY", + "plain": "Int8Array" + }, + { + "base64": "VWludDhBcnJheQ==", + "define": "DUK_STRIDX_UINT8_ARRAY", + "plain": "Uint8Array" + }, + { + "base64": "VWludDhDbGFtcGVkQXJyYXk=", + "define": "DUK_STRIDX_UINT8_CLAMPED_ARRAY", + "plain": "Uint8ClampedArray" + }, + { + "base64": "SW50MTZBcnJheQ==", + "define": "DUK_STRIDX_INT16_ARRAY", + "plain": "Int16Array" + }, + { + "base64": "VWludDE2QXJyYXk=", + "define": "DUK_STRIDX_UINT16_ARRAY", + "plain": "Uint16Array" + }, + { + "base64": "SW50MzJBcnJheQ==", + "define": "DUK_STRIDX_INT32_ARRAY", + "plain": "Int32Array" + }, + { + "base64": "VWludDMyQXJyYXk=", + "define": "DUK_STRIDX_UINT32_ARRAY", + "plain": "Uint32Array" + }, + { + "base64": "RmxvYXQzMkFycmF5", + "define": "DUK_STRIDX_FLOAT32_ARRAY", + "plain": "Float32Array" + }, + { + "base64": "RmxvYXQ2NEFycmF5", + "define": "DUK_STRIDX_FLOAT64_ARRAY", + "plain": "Float64Array" + }, + { + "base64": "Z2xvYmFs", + "define": "DUK_STRIDX_GLOBAL", + "plain": "global" + }, + { + "base64": "T2JqRW52", + "define": "DUK_STRIDX_OBJ_ENV", + "plain": "ObjEnv" + }, + { + "base64": "RGVjRW52", + "define": "DUK_STRIDX_DEC_ENV", + "plain": "DecEnv" + }, + { + "base64": "QnVmZmVy", + "define": "DUK_STRIDX_UC_BUFFER", + "plain": "Buffer" + }, + { + "base64": "UG9pbnRlcg==", + "define": "DUK_STRIDX_UC_POINTER", + "plain": "Pointer" + }, + { + "base64": "VGhyZWFk", + "define": "DUK_STRIDX_UC_THREAD", + "plain": "Thread" + }, + { + "base64": "ZXZhbA==", + "define": "DUK_STRIDX_EVAL", + "plain": "eval" + }, + { + "base64": "ZGVmaW5lUHJvcGVydHk=", + "define": "DUK_STRIDX_DEFINE_PROPERTY", + "plain": "defineProperty" + }, + { + "base64": "dmFsdWU=", + "define": "DUK_STRIDX_VALUE", + "plain": "value" + }, + { + "base64": "d3JpdGFibGU=", + "define": "DUK_STRIDX_WRITABLE", + "plain": "writable" + }, + { + "base64": "Y29uZmlndXJhYmxl", + "define": "DUK_STRIDX_CONFIGURABLE", + "plain": "configurable" + }, + { + "base64": "ZW51bWVyYWJsZQ==", + "define": "DUK_STRIDX_ENUMERABLE", + "plain": "enumerable" + }, + { + "base64": "am9pbg==", + "define": "DUK_STRIDX_JOIN", + "plain": "join" + }, + { + "base64": "dG9Mb2NhbGVTdHJpbmc=", + "define": "DUK_STRIDX_TO_LOCALE_STRING", + "plain": "toLocaleString" + }, + { + "base64": "dmFsdWVPZg==", + "define": "DUK_STRIDX_VALUE_OF", + "plain": "valueOf" + }, + { + "base64": "dG9VVENTdHJpbmc=", + "define": "DUK_STRIDX_TO_UTC_STRING", + "plain": "toUTCString" + }, + { + "base64": "dG9JU09TdHJpbmc=", + "define": "DUK_STRIDX_TO_ISO_STRING", + "plain": "toISOString" + }, + { + "base64": "dG9HTVRTdHJpbmc=", + "define": "DUK_STRIDX_TO_GMT_STRING", + "plain": "toGMTString" + }, + { + "base64": "c291cmNl", + "define": "DUK_STRIDX_SOURCE", + "plain": "source" + }, + { + "base64": "aWdub3JlQ2FzZQ==", + "define": "DUK_STRIDX_IGNORE_CASE", + "plain": "ignoreCase" + }, + { + "base64": "bXVsdGlsaW5l", + "define": "DUK_STRIDX_MULTILINE", + "plain": "multiline" + }, + { + "base64": "bGFzdEluZGV4", + "define": "DUK_STRIDX_LAST_INDEX", + "plain": "lastIndex" + }, + { + "base64": "KD86KQ==", + "define": "DUK_STRIDX_ESCAPED_EMPTY_REGEXP", + "plain": "(?:)" + }, + { + "base64": "aW5kZXg=", + "define": "DUK_STRIDX_INDEX", + "plain": "index" + }, + { + "base64": "cHJvdG90eXBl", + "define": "DUK_STRIDX_PROTOTYPE", + "plain": "prototype" + }, + { + "base64": "Y29uc3RydWN0b3I=", + "define": "DUK_STRIDX_CONSTRUCTOR", + "plain": "constructor" + }, + { + "base64": "bWVzc2FnZQ==", + "define": "DUK_STRIDX_MESSAGE", + "plain": "message" + }, + { + "base64": "Ym9vbGVhbg==", + "define": "DUK_STRIDX_LC_BOOLEAN", + "plain": "boolean" + }, + { + "base64": "bnVtYmVy", + "define": "DUK_STRIDX_LC_NUMBER", + "plain": "number" + }, + { + "base64": "c3RyaW5n", + "define": "DUK_STRIDX_LC_STRING", + "plain": "string" + }, + { + "base64": "b2JqZWN0", + "define": "DUK_STRIDX_LC_OBJECT", + "plain": "object" + }, + { + "base64": "dW5kZWZpbmVk", + "define": "DUK_STRIDX_LC_UNDEFINED", + "plain": "undefined" + }, + { + "base64": "TmFO", + "define": "DUK_STRIDX_NAN", + "plain": "NaN" + }, + { + "base64": "SW5maW5pdHk=", + "define": "DUK_STRIDX_INFINITY", + "plain": "Infinity" + }, + { + "base64": "LUluZmluaXR5", + "define": "DUK_STRIDX_MINUS_INFINITY", + "plain": "-Infinity" + }, + { + "base64": "LTA=", + "define": "DUK_STRIDX_MINUS_ZERO", + "plain": "-0" + }, + { + "base64": "LA==", + "define": "DUK_STRIDX_COMMA", + "plain": "," + }, + { + "base64": "IA==", + "define": "DUK_STRIDX_SPACE", + "plain": " " + }, + { + "base64": "CiAgICA=", + "define": "DUK_STRIDX_NEWLINE_4SPACE", + "plain": "\n " + }, + { + "base64": "Wy4uLl0=", + "define": "DUK_STRIDX_BRACKETED_ELLIPSIS", + "plain": "[...]" + }, + { + "base64": "SW52YWxpZCBEYXRl", + "define": "DUK_STRIDX_INVALID_DATE", + "plain": "Invalid Date" + }, + { + "base64": "YXJndW1lbnRz", + "define": "DUK_STRIDX_LC_ARGUMENTS", + "plain": "arguments" + }, + { + "base64": "Y2FsbGVl", + "define": "DUK_STRIDX_CALLEE", + "plain": "callee" + }, + { + "base64": "Y2FsbGVy", + "define": "DUK_STRIDX_CALLER", + "plain": "caller" + }, + { + "base64": "aGFz", + "define": "DUK_STRIDX_HAS", + "plain": "has" + }, + { + "base64": "Z2V0", + "define": "DUK_STRIDX_GET", + "plain": "get" + }, + { + "base64": "ZGVsZXRlUHJvcGVydHk=", + "define": "DUK_STRIDX_DELETE_PROPERTY", + "plain": "deleteProperty" + }, + { + "base64": "ZW51bWVyYXRl", + "define": "DUK_STRIDX_ENUMERATE", + "plain": "enumerate" + }, + { + "base64": "b3duS2V5cw==", + "define": "DUK_STRIDX_OWN_KEYS", + "plain": "ownKeys" + }, + { + "base64": "c2V0UHJvdG90eXBlT2Y=", + "define": "DUK_STRIDX_SET_PROTOTYPE_OF", + "plain": "setPrototypeOf" + }, + { + "base64": "X19wcm90b19f", + "define": "DUK_STRIDX___PROTO__", + "plain": "__proto__" + }, + { + "base64": "cmVxdWlyZQ==", + "define": "DUK_STRIDX_REQUIRE", + "plain": "require" + }, + { + "base64": "aWQ=", + "define": "DUK_STRIDX_ID", + "plain": "id" + }, + { + "base64": "ZXhwb3J0cw==", + "define": "DUK_STRIDX_EXPORTS", + "plain": "exports" + }, + { + "base64": "ZmlsZW5hbWU=", + "define": "DUK_STRIDX_FILENAME", + "plain": "filename" + }, + { + "base64": "dG9TdHJpbmc=", + "define": "DUK_STRIDX_TO_STRING", + "plain": "toString" + }, + { + "base64": "dG9KU09O", + "define": "DUK_STRIDX_TO_JSON", + "plain": "toJSON" + }, + { + "base64": "dHlwZQ==", + "define": "DUK_STRIDX_TYPE", + "plain": "type" + }, + { + "base64": "ZGF0YQ==", + "define": "DUK_STRIDX_DATA", + "plain": "data" + }, + { + "base64": "bGVuZ3Ro", + "define": "DUK_STRIDX_LENGTH", + "plain": "length" + }, + { + "base64": "Ynl0ZUxlbmd0aA==", + "define": "DUK_STRIDX_BYTE_LENGTH", + "plain": "byteLength" + }, + { + "base64": "Ynl0ZU9mZnNldA==", + "define": "DUK_STRIDX_BYTE_OFFSET", + "plain": "byteOffset" + }, + { + "base64": "QllURVNfUEVSX0VMRU1FTlQ=", + "define": "DUK_STRIDX_BYTES_PER_ELEMENT", + "plain": "BYTES_PER_ELEMENT" + }, + { + "base64": "c2V0", + "define": "DUK_STRIDX_SET", + "plain": "set" + }, + { + "base64": "c3RhY2s=", + "define": "DUK_STRIDX_STACK", + "plain": "stack" + }, + { + "base64": "cGM=", + "define": "DUK_STRIDX_PC", + "plain": "pc" + }, + { + "base64": "bGluZU51bWJlcg==", + "define": "DUK_STRIDX_LINE_NUMBER", + "plain": "lineNumber" + }, + { + "base64": "/1RyYWNlZGF0YQ==", + "define": "DUK_STRIDX_INT_TRACEDATA", + "plain": "\u00ffTracedata" + }, + { + "base64": "bmFtZQ==", + "define": "DUK_STRIDX_NAME", + "plain": "name" + }, + { + "base64": "ZmlsZU5hbWU=", + "define": "DUK_STRIDX_FILE_NAME", + "plain": "fileName" + }, + { + "base64": "YnVmZmVy", + "define": "DUK_STRIDX_LC_BUFFER", + "plain": "buffer" + }, + { + "base64": "cG9pbnRlcg==", + "define": "DUK_STRIDX_LC_POINTER", + "plain": "pointer" + }, + { + "base64": "/1ZhbHVl", + "define": "DUK_STRIDX_INT_VALUE", + "plain": "\u00ffValue" + }, + { + "base64": "/05leHQ=", + "define": "DUK_STRIDX_INT_NEXT", + "plain": "\u00ffNext" + }, + { + "base64": "/0J5dGVjb2Rl", + "define": "DUK_STRIDX_INT_BYTECODE", + "plain": "\u00ffBytecode" + }, + { + "base64": "/0Zvcm1hbHM=", + "define": "DUK_STRIDX_INT_FORMALS", + "plain": "\u00ffFormals" + }, + { + "base64": "/1Zhcm1hcA==", + "define": "DUK_STRIDX_INT_VARMAP", + "plain": "\u00ffVarmap" + }, + { + "base64": "/0xleGVudg==", + "define": "DUK_STRIDX_INT_LEXENV", + "plain": "\u00ffLexenv" + }, + { + "base64": "/1ZhcmVudg==", + "define": "DUK_STRIDX_INT_VARENV", + "plain": "\u00ffVarenv" + }, + { + "base64": "/1NvdXJjZQ==", + "define": "DUK_STRIDX_INT_SOURCE", + "plain": "\u00ffSource" + }, + { + "base64": "/1BjMmxpbmU=", + "define": "DUK_STRIDX_INT_PC2LINE", + "plain": "\u00ffPc2line" + }, + { + "base64": "/0FyZ3M=", + "define": "DUK_STRIDX_INT_ARGS", + "plain": "\u00ffArgs" + }, + { + "base64": "/01hcA==", + "define": "DUK_STRIDX_INT_MAP", + "plain": "\u00ffMap" + }, + { + "base64": "/0ZpbmFsaXplcg==", + "define": "DUK_STRIDX_INT_FINALIZER", + "plain": "\u00ffFinalizer" + }, + { + "base64": "/0hhbmRsZXI=", + "define": "DUK_STRIDX_INT_HANDLER", + "plain": "\u00ffHandler" + }, + { + "base64": "/0NhbGxlZQ==", + "define": "DUK_STRIDX_INT_CALLEE", + "plain": "\u00ffCallee" + }, + { + "base64": "/1RocmVhZA==", + "define": "DUK_STRIDX_INT_THREAD", + "plain": "\u00ffThread" + }, + { + "base64": "/1JlZ2Jhc2U=", + "define": "DUK_STRIDX_INT_REGBASE", + "plain": "\u00ffRegbase" + }, + { + "base64": "/1RhcmdldA==", + "define": "DUK_STRIDX_INT_TARGET", + "plain": "\u00ffTarget" + }, + { + "base64": "/1RoaXM=", + "define": "DUK_STRIDX_INT_THIS", + "plain": "\u00ffThis" + }, + { + "base64": "Y29tcGlsZQ==", + "define": "DUK_STRIDX_COMPILE", + "plain": "compile" + }, + { + "base64": "aW5wdXQ=", + "define": "DUK_STRIDX_INPUT", + "plain": "input" + }, + { + "base64": "ZXJyQ3JlYXRl", + "define": "DUK_STRIDX_ERR_CREATE", + "plain": "errCreate" + }, + { + "base64": "ZXJyVGhyb3c=", + "define": "DUK_STRIDX_ERR_THROW", + "plain": "errThrow" + }, + { + "base64": "bW9kU2VhcmNo", + "define": "DUK_STRIDX_MOD_SEARCH", + "plain": "modSearch" + }, + { + "base64": "bW9kTG9hZGVk", + "define": "DUK_STRIDX_MOD_LOADED", + "plain": "modLoaded" + }, + { + "base64": "ZW52", + "define": "DUK_STRIDX_ENV", + "plain": "env" + }, + { + "base64": "aGV4", + "define": "DUK_STRIDX_HEX", + "plain": "hex" + }, + { + "base64": "YmFzZTY0", + "define": "DUK_STRIDX_BASE64", + "plain": "base64" + }, + { + "base64": "ang=", + "define": "DUK_STRIDX_JX", + "plain": "jx" + }, + { + "base64": "amM=", + "define": "DUK_STRIDX_JC", + "plain": "jc" + }, + { + "base64": "cmVzdW1l", + "define": "DUK_STRIDX_RESUME", + "plain": "resume" + }, + { + "base64": "Zm10", + "define": "DUK_STRIDX_FMT", + "plain": "fmt" + }, + { + "base64": "cmF3", + "define": "DUK_STRIDX_RAW", + "plain": "raw" + }, + { + "base64": "dHJhY2U=", + "define": "DUK_STRIDX_LC_TRACE", + "plain": "trace" + }, + { + "base64": "ZGVidWc=", + "define": "DUK_STRIDX_LC_DEBUG", + "plain": "debug" + }, + { + "base64": "aW5mbw==", + "define": "DUK_STRIDX_LC_INFO", + "plain": "info" + }, + { + "base64": "d2Fybg==", + "define": "DUK_STRIDX_LC_WARN", + "plain": "warn" + }, + { + "base64": "ZXJyb3I=", + "define": "DUK_STRIDX_LC_ERROR", + "plain": "error" + }, + { + "base64": "ZmF0YWw=", + "define": "DUK_STRIDX_LC_FATAL", + "plain": "fatal" + }, + { + "base64": "bg==", + "define": "DUK_STRIDX_LC_N", + "plain": "n" + }, + { + "base64": "bA==", + "define": "DUK_STRIDX_LC_L", + "plain": "l" + }, + { + "base64": "Y2xvZw==", + "define": "DUK_STRIDX_CLOG", + "plain": "clog" + }, + { + "base64": "dG9Mb2dTdHJpbmc=", + "define": "DUK_STRIDX_TO_LOG_STRING", + "plain": "toLogString" + }, + { + "base64": "eyJfdW5kZWYiOnRydWV9", + "define": "DUK_STRIDX_JSON_EXT_UNDEFINED", + "plain": "{\"_undef\":true}" + }, + { + "base64": "eyJfbmFuIjp0cnVlfQ==", + "define": "DUK_STRIDX_JSON_EXT_NAN", + "plain": "{\"_nan\":true}" + }, + { + "base64": "eyJfaW5mIjp0cnVlfQ==", + "define": "DUK_STRIDX_JSON_EXT_POSINF", + "plain": "{\"_inf\":true}" + }, + { + "base64": "eyJfbmluZiI6dHJ1ZX0=", + "define": "DUK_STRIDX_JSON_EXT_NEGINF", + "plain": "{\"_ninf\":true}" + }, + { + "base64": "eyJfZnVuYyI6dHJ1ZX0=", + "define": "DUK_STRIDX_JSON_EXT_FUNCTION1", + "plain": "{\"_func\":true}" + }, + { + "base64": "e19mdW5jOnRydWV9", + "define": "DUK_STRIDX_JSON_EXT_FUNCTION2", + "plain": "{_func:true}" + }, + { + "base64": "YnJlYWs=", + "define": "DUK_STRIDX_BREAK", + "plain": "break" + }, + { + "base64": "Y2FzZQ==", + "define": "DUK_STRIDX_CASE", + "plain": "case" + }, + { + "base64": "Y2F0Y2g=", + "define": "DUK_STRIDX_CATCH", + "plain": "catch" + }, + { + "base64": "Y29udGludWU=", + "define": "DUK_STRIDX_CONTINUE", + "plain": "continue" + }, + { + "base64": "ZGVidWdnZXI=", + "define": "DUK_STRIDX_DEBUGGER", + "plain": "debugger" + }, + { + "base64": "ZGVmYXVsdA==", + "define": "DUK_STRIDX_DEFAULT", + "plain": "default" + }, + { + "base64": "ZGVsZXRl", + "define": "DUK_STRIDX_DELETE", + "plain": "delete" + }, + { + "base64": "ZG8=", + "define": "DUK_STRIDX_DO", + "plain": "do" + }, + { + "base64": "ZWxzZQ==", + "define": "DUK_STRIDX_ELSE", + "plain": "else" + }, + { + "base64": "ZmluYWxseQ==", + "define": "DUK_STRIDX_FINALLY", + "plain": "finally" + }, + { + "base64": "Zm9y", + "define": "DUK_STRIDX_FOR", + "plain": "for" + }, + { + "base64": "ZnVuY3Rpb24=", + "define": "DUK_STRIDX_LC_FUNCTION", + "plain": "function" + }, + { + "base64": "aWY=", + "define": "DUK_STRIDX_IF", + "plain": "if" + }, + { + "base64": "aW4=", + "define": "DUK_STRIDX_IN", + "plain": "in" + }, + { + "base64": "aW5zdGFuY2VvZg==", + "define": "DUK_STRIDX_INSTANCEOF", + "plain": "instanceof" + }, + { + "base64": "bmV3", + "define": "DUK_STRIDX_NEW", + "plain": "new" + }, + { + "base64": "cmV0dXJu", + "define": "DUK_STRIDX_RETURN", + "plain": "return" + }, + { + "base64": "c3dpdGNo", + "define": "DUK_STRIDX_SWITCH", + "plain": "switch" + }, + { + "base64": "dGhpcw==", + "define": "DUK_STRIDX_THIS", + "plain": "this" + }, + { + "base64": "dGhyb3c=", + "define": "DUK_STRIDX_THROW", + "plain": "throw" + }, + { + "base64": "dHJ5", + "define": "DUK_STRIDX_TRY", + "plain": "try" + }, + { + "base64": "dHlwZW9m", + "define": "DUK_STRIDX_TYPEOF", + "plain": "typeof" + }, + { + "base64": "dmFy", + "define": "DUK_STRIDX_VAR", + "plain": "var" + }, + { + "base64": "Y29uc3Q=", + "define": "DUK_STRIDX_CONST", + "plain": "const" + }, + { + "base64": "dm9pZA==", + "define": "DUK_STRIDX_VOID", + "plain": "void" + }, + { + "base64": "d2hpbGU=", + "define": "DUK_STRIDX_WHILE", + "plain": "while" + }, + { + "base64": "d2l0aA==", + "define": "DUK_STRIDX_WITH", + "plain": "with" + }, + { + "base64": "Y2xhc3M=", + "define": "DUK_STRIDX_CLASS", + "plain": "class" + }, + { + "base64": "ZW51bQ==", + "define": "DUK_STRIDX_ENUM", + "plain": "enum" + }, + { + "base64": "ZXhwb3J0", + "define": "DUK_STRIDX_EXPORT", + "plain": "export" + }, + { + "base64": "ZXh0ZW5kcw==", + "define": "DUK_STRIDX_EXTENDS", + "plain": "extends" + }, + { + "base64": "aW1wb3J0", + "define": "DUK_STRIDX_IMPORT", + "plain": "import" + }, + { + "base64": "c3VwZXI=", + "define": "DUK_STRIDX_SUPER", + "plain": "super" + }, + { + "base64": "bnVsbA==", + "define": "DUK_STRIDX_LC_NULL", + "plain": "null" + }, + { + "base64": "dHJ1ZQ==", + "define": "DUK_STRIDX_TRUE", + "plain": "true" + }, + { + "base64": "ZmFsc2U=", + "define": "DUK_STRIDX_FALSE", + "plain": "false" + }, + { + "base64": "aW1wbGVtZW50cw==", + "define": "DUK_STRIDX_IMPLEMENTS", + "plain": "implements" + }, + { + "base64": "aW50ZXJmYWNl", + "define": "DUK_STRIDX_INTERFACE", + "plain": "interface" + }, + { + "base64": "bGV0", + "define": "DUK_STRIDX_LET", + "plain": "let" + }, + { + "base64": "cGFja2FnZQ==", + "define": "DUK_STRIDX_PACKAGE", + "plain": "package" + }, + { + "base64": "cHJpdmF0ZQ==", + "define": "DUK_STRIDX_PRIVATE", + "plain": "private" + }, + { + "base64": "cHJvdGVjdGVk", + "define": "DUK_STRIDX_PROTECTED", + "plain": "protected" + }, + { + "base64": "cHVibGlj", + "define": "DUK_STRIDX_PUBLIC", + "plain": "public" + }, + { + "base64": "c3RhdGlj", + "define": "DUK_STRIDX_STATIC", + "plain": "static" + }, + { + "base64": "eWllbGQ=", + "define": "DUK_STRIDX_YIELD", + "plain": "yield" + } + ], + "comment": "Metadata for Duktape build", + "duk_version": 10502, + "duk_version_string": "1.5.2", + "git_describe": "v1.5.2" +} \ No newline at end of file diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-hybrid/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-hybrid/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-hybrid/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-hybrid/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-hybrid/duk_alloc_hybrid.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-hybrid/duk_alloc_hybrid.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-hybrid/duk_alloc_hybrid.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-hybrid/duk_alloc_hybrid.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-hybrid/duk_alloc_hybrid.h b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-hybrid/duk_alloc_hybrid.h similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-hybrid/duk_alloc_hybrid.h rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-hybrid/duk_alloc_hybrid.h diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/duk_alloc_logging.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/duk_alloc_logging.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/duk_alloc_logging.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/duk_alloc_logging.c index 86fecc56c..a89babf92 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/duk_alloc_logging.c +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/duk_alloc_logging.c @@ -90,8 +90,8 @@ void *duk_realloc_logging(void *udata, void *ptr, duk_size_t size) { old_size = hdr->u.sz; if (size == 0) { - free((void *) hdr); write_log("R %p %ld NULL 0\n", ptr, (long) old_size); + free((void *) hdr); return NULL; } else { t = realloc((void *) hdr, size + sizeof(alloc_hdr)); diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/duk_alloc_logging.h b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/duk_alloc_logging.h similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/duk_alloc_logging.h rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/duk_alloc_logging.h diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/log2gnuplot.py b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/log2gnuplot.py similarity index 97% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/log2gnuplot.py rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/log2gnuplot.py index 7562814d3..0528259dc 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-logging/log2gnuplot.py +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-logging/log2gnuplot.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 # # Analyze allocator logs and write total-bytes-in-use after every # operation to stdout. The output can be gnuplotted as: diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-torture/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-torture/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-torture/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-torture/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-torture/duk_alloc_torture.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-torture/duk_alloc_torture.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-torture/duk_alloc_torture.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-torture/duk_alloc_torture.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-torture/duk_alloc_torture.h b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-torture/duk_alloc_torture.h similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/alloc-torture/duk_alloc_torture.h rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/alloc-torture/duk_alloc_torture.h diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/cmdline/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cmdline/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/cmdline/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cmdline/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/cmdline/duk_cmdline.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cmdline/duk_cmdline.c similarity index 50% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/cmdline/duk_cmdline.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cmdline/duk_cmdline.c index df61cdf9a..ea5af55e8 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/cmdline/duk_cmdline.c +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cmdline/duk_cmdline.c @@ -1,21 +1,31 @@ /* * Command line execution tool. Useful for test cases and manual testing. * - * To enable readline and other fancy stuff, compile with -DDUK_CMDLINE_FANCY. + * To enable linenoise and other fancy stuff, compile with -DDUK_CMDLINE_FANCY. * It is not the default to maximize portability. You can also compile in * support for example allocators, grep for DUK_CMDLINE_*. */ -#ifndef DUK_CMDLINE_FANCY -#define NO_READLINE -#define NO_RLIMIT -#define NO_SIGNAL +/* Helper define to enable a feature set; can also use separate defines. */ +#if defined(DUK_CMDLINE_FANCY) +#define DUK_CMDLINE_LINENOISE +#define DUK_CMDLINE_LINENOISE_COMPLETION +#define DUK_CMDLINE_RLIMIT +#define DUK_CMDLINE_SIGNAL #endif #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \ defined(WIN64) || defined(_WIN64) || defined(__WIN64__) /* Suppress warnings about plain fopen() etc. */ #define _CRT_SECURE_NO_WARNINGS +#if defined(_MSC_VER) && (_MSC_VER < 1900) +/* Workaround for snprintf() missing in older MSVC versions. + * Note that _snprintf() may not NUL terminate the string, but + * this difference does not matter here as a NUL terminator is + * always explicitly added. + */ +#define snprintf _snprintf +#endif #endif #define GREET_CODE(variant) \ @@ -28,30 +38,36 @@ #include #include #include -#ifndef NO_SIGNAL +#if defined(DUK_CMDLINE_SIGNAL) #include #endif -#ifndef NO_RLIMIT +#if defined(DUK_CMDLINE_RLIMIT) #include #endif -#ifndef NO_READLINE -#include -#include +#if defined(DUK_CMDLINE_LINENOISE) +#include "linenoise.h" #endif -#ifdef DUK_CMDLINE_ALLOC_LOGGING +#if defined(DUK_CMDLINE_FILEIO) +#include +#endif +#if defined(EMSCRIPTEN) +#include +#endif +#if defined(DUK_CMDLINE_ALLOC_LOGGING) #include "duk_alloc_logging.h" #endif -#ifdef DUK_CMDLINE_ALLOC_TORTURE +#if defined(DUK_CMDLINE_ALLOC_TORTURE) #include "duk_alloc_torture.h" #endif -#ifdef DUK_CMDLINE_ALLOC_HYBRID +#if defined(DUK_CMDLINE_ALLOC_HYBRID) #include "duk_alloc_hybrid.h" #endif #include "duktape.h" -#ifdef DUK_CMDLINE_AJSHEAP +#if defined(DUK_CMDLINE_AJSHEAP) /* Defined in duk_cmdline_ajduk.c or alljoyn.js headers. */ void ajsheap_init(void); +void ajsheap_free(void); void ajsheap_dump(void); void ajsheap_register(duk_context *ctx); void ajsheap_start_exec_timeout(void); @@ -64,7 +80,7 @@ void *AJS_Realloc(void *udata, void *ptr, duk_size_t size); void AJS_Free(void *udata, void *ptr); #endif -#ifdef DUK_CMDLINE_DEBUGGER_SUPPORT +#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) #include "duk_trans_socket.h" #endif @@ -72,9 +88,18 @@ void AJS_Free(void *udata, void *ptr); #define MEM_LIMIT_HIGH (2047*1024*1024) /* ~2 GB */ #define LINEBUF_SIZE 65536 +static int main_argc = 0; +static char **main_argv = NULL; static int interactive_mode = 0; +#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) +static int debugger_reattach = 0; +#endif -#ifndef NO_RLIMIT +/* + * Misc helpers + */ + +#if defined(DUK_CMDLINE_RLIMIT) static void set_resource_limits(rlim_t mem_limit_value) { int rc; struct rlimit lim; @@ -103,17 +128,18 @@ static void set_resource_limits(rlim_t mem_limit_value) { fprintf(stderr, "Set RLIMIT_AS to %d\n", (int) mem_limit_value); #endif } -#endif /* NO_RLIMIT */ +#endif /* DUK_CMDLINE_RLIMIT */ -#ifndef NO_SIGNAL +#if defined(DUK_CMDLINE_SIGNAL) static void my_sighandler(int x) { fprintf(stderr, "Got signal %d\n", x); fflush(stderr); } static void set_sigint_handler(void) { (void) signal(SIGINT, my_sighandler); + (void) signal(SIGPIPE, SIG_IGN); /* avoid SIGPIPE killing process */ } -#endif /* NO_SIGNAL */ +#endif /* DUK_CMDLINE_SIGNAL */ static int get_stack_raw(duk_context *ctx) { if (!duk_is_object(ctx, -1)) { @@ -183,11 +209,25 @@ static int wrapped_compile_execute(duk_context *ctx) { void *bc_ptr; duk_size_t bc_len; size_t wrote; + char fnbuf[256]; + const char *filename; duk_dup_top(ctx); duk_dump_function(ctx); bc_ptr = duk_require_buffer(ctx, -1, &bc_len); - f = fopen(duk_require_string(ctx, -5), "wb"); + filename = duk_require_string(ctx, -5); +#if defined(EMSCRIPTEN) + if (filename[0] == '/') { + snprintf(fnbuf, sizeof(fnbuf), "%s", filename); + } else { + snprintf(fnbuf, sizeof(fnbuf), "/working/%s", filename); + } +#else + snprintf(fnbuf, sizeof(fnbuf), "%s", filename); +#endif + fnbuf[sizeof(fnbuf) - 1] = (char) 0; + + f = fopen(fnbuf, "wb"); if (!f) { duk_error(ctx, DUK_ERR_ERROR, "failed to open bytecode output file"); } @@ -253,30 +293,295 @@ static int wrapped_compile_execute(duk_context *ctx) { return 0; /* duk_safe_call() cleans up */ } +/* + * Minimal Linenoise completion support + */ + +#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) +static duk_context *completion_ctx; + +static int completion_idpart(unsigned char c) { + /* Very simplified "is identifier part" check. */ + if ((c >= (unsigned char) 'a' && c <= (unsigned char) 'z') || + (c >= (unsigned char) 'A' && c <= (unsigned char) 'Z') || + (c >= (unsigned char) '0' && c <= (unsigned char) '9') || + c == (unsigned char) '$' || c == (unsigned char) '_') { + return 1; + } + return 0; +} + +static int completion_digit(unsigned char c) { + return (c >= (unsigned char) '0' && c <= (unsigned char) '9'); +} + +static duk_ret_t linenoise_completion_lookup(duk_context *ctx) { + duk_size_t len; + const char *orig; + const unsigned char *p; + const unsigned char *p_curr; + const unsigned char *p_end; + const char *key; + const char *prefix; + linenoiseCompletions *lc; + duk_idx_t idx_obj; + + orig = duk_require_string(ctx, -3); + p_curr = (const unsigned char *) duk_require_lstring(ctx, -2, &len); + p_end = p_curr + len; + lc = duk_require_pointer(ctx, -1); + + duk_push_global_object(ctx); + idx_obj = duk_require_top_index(ctx); + + while (p_curr <= p_end) { + /* p_curr == p_end allowed on purpose, to handle 'Math.' for example. */ + p = p_curr; + while (p < p_end && p[0] != (unsigned char) '.') { + p++; + } + /* 'p' points to a NUL (p == p_end) or a period. */ + prefix = duk_push_lstring(ctx, (const char *) p_curr, (duk_size_t) (p - p_curr)); + +#if 0 + fprintf(stderr, "Completion check: '%s'\n", prefix); + fflush(stderr); +#endif + + if (p == p_end) { + /* 'idx_obj' points to the object matching the last + * full component, use [p_curr,p[ as a filter for + * that object. + */ + + duk_enum(ctx, idx_obj, DUK_ENUM_INCLUDE_NONENUMERABLE); + while (duk_next(ctx, -1, 0 /*get_value*/)) { + key = duk_get_string(ctx, -1); +#if 0 + fprintf(stderr, "Key: %s\n", key ? key : ""); + fflush(stderr); +#endif + if (!key) { + /* Should never happen, just in case. */ + goto next; + } + + /* Ignore array index keys: usually not desirable, and would + * also require ['0'] quoting. + */ + if (completion_digit(key[0])) { + goto next; + } + + /* XXX: There's no key quoting now, it would require replacing the + * last component with a ['foo\nbar'] style lookup when appropriate. + */ + + if (strlen(prefix) == 0) { + /* Partial ends in a period, e.g. 'Math.' -> complete all Math properties. */ + duk_push_string(ctx, orig); /* original, e.g. 'Math.' */ + duk_push_string(ctx, key); + duk_concat(ctx, 2); + linenoiseAddCompletion(lc, duk_require_string(ctx, -1)); + duk_pop(ctx); + } else if (prefix && strcmp(key, prefix) == 0) { + /* Full completion, add a period, e.g. input 'Math' -> 'Math.'. */ + duk_push_string(ctx, orig); /* original, including partial last component */ + duk_push_string(ctx, "."); + duk_concat(ctx, 2); + linenoiseAddCompletion(lc, duk_require_string(ctx, -1)); + duk_pop(ctx); + } else if (prefix && strncmp(key, prefix, strlen(prefix)) == 0) { + /* Last component is partial, complete. */ + duk_push_string(ctx, orig); /* original, including partial last component */ + duk_push_string(ctx, key + strlen(prefix)); /* completion to last component */ + duk_concat(ctx, 2); + linenoiseAddCompletion(lc, duk_require_string(ctx, -1)); + duk_pop(ctx); + } + + next: + duk_pop(ctx); + } + return 0; + } else { + if (duk_get_prop(ctx, idx_obj)) { + duk_to_object(ctx, -1); /* for properties of plain strings etc */ + duk_replace(ctx, idx_obj); + p_curr = p + 1; + } else { + /* Not found. */ + return 0; + } + } + } + + return 0; +} + +static void linenoise_completion(const char *buf, linenoiseCompletions *lc) { + duk_context *ctx; + const unsigned char *p_start; + const unsigned char *p_end; + const unsigned char *p; + duk_int_t rc; + + if (!buf) { + return; + } + ctx = completion_ctx; + if (!ctx) { + return; + } + + p_start = (const unsigned char *) buf; + p_end = (const unsigned char *) (buf + strlen(buf)); + p = p_end; + + /* Scan backwards for a maximal string which looks like a property + * chain (e.g. foo.bar.quux). + */ + + while (--p >= p_start) { + if (p[0] == (unsigned char) '.') { + if (p <= p_start) { + break; + } + if (!completion_idpart(p[-1])) { + /* Catches e.g. 'foo..bar' -> we want 'bar' only. */ + break; + } + } else if (!completion_idpart(p[0])) { + break; + } + } + /* 'p' will either be p_start - 1 (ran out of buffer) or point to + * the first offending character. + */ + p++; + if (p < p_start || p >= p_end) { + return; /* should never happen, but just in case */ + } + + /* 'p' now points to a string of the form 'foo.bar.quux'. Look up + * all the components except the last; treat the last component as + * a partial name which is used as a filter for the previous full + * component. All lookups are from the global object now. + */ + +#if 0 + fprintf(stderr, "Completion starting point: '%s'\n", p); + fflush(stderr); +#endif + + duk_push_string(ctx, (const char *) buf); + duk_push_lstring(ctx, (const char *) p, (duk_size_t) (p_end - p)); + duk_push_pointer(ctx, (void *) lc); + + rc = duk_safe_call(ctx, linenoise_completion_lookup, 3 /*nargs*/, 1 /*nrets*/); + if (rc != DUK_EXEC_SUCCESS) { + fprintf(stderr, "Completion handling failure: %s\n", duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); +} +#endif /* DUK_CMDLINE_LINENOISE_COMPLETION */ + +/* + * Execute from file handle etc + */ + static int handle_fh(duk_context *ctx, FILE *f, const char *filename, const char *bytecode_filename) { char *buf = NULL; - int len; + size_t bufsz; + size_t bufoff; size_t got; int rc; int retval = -1; - if (fseek(f, 0, SEEK_END) < 0) { - goto error; - } - len = (int) ftell(f); - if (fseek(f, 0, SEEK_SET) < 0) { - goto error; - } - buf = (char *) malloc(len); + buf = (char *) malloc(1024); if (!buf) { goto error; } + bufsz = 1024; + bufoff = 0; - got = fread((void *) buf, (size_t) 1, (size_t) len, f); + /* Read until EOF, avoid fseek/stat because it won't work with stdin. */ + for (;;) { + size_t avail; + + avail = bufsz - bufoff; + if (avail < 1024) { + size_t newsz; + char *buf_new; +#if 0 + fprintf(stderr, "resizing read buffer: %ld -> %ld\n", (long) bufsz, (long) (bufsz * 2)); +#endif + newsz = bufsz + (bufsz >> 2) + 1024; /* +25% and some extra */ + buf_new = (char *) realloc(buf, newsz); + if (!buf_new) { + goto error; + } + buf = buf_new; + bufsz = newsz; + } + + avail = bufsz - bufoff; +#if 0 + fprintf(stderr, "reading input: buf=%p bufsz=%ld bufoff=%ld avail=%ld\n", + (void *) buf, (long) bufsz, (long) bufoff, (long) avail); +#endif + + got = fread((void *) (buf + bufoff), (size_t) 1, avail, f); +#if 0 + fprintf(stderr, "got=%ld\n", (long) got); +#endif + if (got == 0) { + break; + } + bufoff += got; + + /* Emscripten specific: stdin EOF doesn't work as expected. + * Instead, when 'emduk' is executed using Node.js, a file + * piped to stdin repeats (!). Detect that repeat and cut off + * the stdin read. Ensure the loop repeats enough times to + * avoid detecting spurious loops. + * + * This only seems to work for inputs up to 256 bytes long. + */ +#if defined(EMSCRIPTEN) + if (bufoff >= 16384) { + size_t i, j, nloops; + int looped = 0; + + for (i = 16; i < bufoff / 8; i++) { + int ok; + + nloops = bufoff / i; + ok = 1; + for (j = 1; j < nloops; j++) { + if (memcmp((void *) buf, (void *) (buf + i * j), i) != 0) { + ok = 0; + break; + } + } + if (ok) { + fprintf(stderr, "emscripten workaround: detect looping at index %ld, verified with %ld loops\n", (long) i, (long) (nloops - 1)); + bufoff = i; + looped = 1; + break; + } + } + + if (looped) { + break; + } + } +#endif + } duk_push_string(ctx, bytecode_filename); duk_push_pointer(ctx, (void *) buf); - duk_push_uint(ctx, (duk_uint_t) got); + duk_push_uint(ctx, (duk_uint_t) bufoff); duk_push_string(ctx, filename); interactive_mode = 0; /* global */ @@ -302,6 +607,7 @@ static int handle_fh(duk_context *ctx, FILE *f, const char *filename, const char cleanup: if (buf) { free(buf); + buf = NULL; } return retval; @@ -314,8 +620,25 @@ static int handle_fh(duk_context *ctx, FILE *f, const char *filename, const char static int handle_file(duk_context *ctx, const char *filename, const char *bytecode_filename) { FILE *f = NULL; int retval; + char fnbuf[256]; - f = fopen(filename, "rb"); + /* Example of sending an application specific debugger notification. */ + duk_push_string(ctx, "DebuggerHandleFile"); + duk_push_string(ctx, filename); + duk_debugger_notify(ctx, 2); + +#if defined(EMSCRIPTEN) + if (filename[0] == '/') { + snprintf(fnbuf, sizeof(fnbuf), "%s", filename); + } else { + snprintf(fnbuf, sizeof(fnbuf), "/working/%s", filename); + } +#else + snprintf(fnbuf, sizeof(fnbuf), "%s", filename); +#endif + fnbuf[sizeof(fnbuf) - 1] = (char) 0; + + f = fopen(fnbuf, "rb"); if (!f) { fprintf(stderr, "failed to open source file: %s\n", filename); fflush(stderr); @@ -331,7 +654,7 @@ static int handle_file(duk_context *ctx, const char *filename, const char *bytec return -1; } -static int handle_eval(duk_context *ctx, const char *code) { +static int handle_eval(duk_context *ctx, char *code) { int rc; int retval = -1; @@ -357,7 +680,78 @@ static int handle_eval(duk_context *ctx, const char *code) { return retval; } -#ifdef NO_READLINE +#if defined(DUK_CMDLINE_LINENOISE) +static int handle_interactive(duk_context *ctx) { + const char *prompt = "duk> "; + char *buffer = NULL; + int retval = 0; + int rc; + + duk_eval_string(ctx, GREET_CODE(" [linenoise]")); + duk_pop(ctx); + + linenoiseSetMultiLine(1); + linenoiseHistorySetMaxLen(64); +#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) + linenoiseSetCompletionCallback(linenoise_completion); +#endif + + for (;;) { + if (buffer) { + linenoiseFree(buffer); + buffer = NULL; + } + +#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) + completion_ctx = ctx; +#endif + buffer = linenoise(prompt); +#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) + completion_ctx = NULL; +#endif + + if (!buffer) { + break; + } + + if (buffer && buffer[0] != (char) 0) { + linenoiseHistoryAdd(buffer); + } + + duk_push_pointer(ctx, (void *) buffer); + duk_push_uint(ctx, (duk_uint_t) strlen(buffer)); + duk_push_string(ctx, "input"); + + interactive_mode = 1; /* global */ + + rc = duk_safe_call(ctx, wrapped_compile_execute, 3 /*nargs*/, 1 /*nret*/); + +#if defined(DUK_CMDLINE_AJSHEAP) + ajsheap_clear_exec_timeout(); +#endif + + if (buffer) { + linenoiseFree(buffer); + buffer = NULL; + } + + if (rc != DUK_EXEC_SUCCESS) { + /* in interactive mode, write to stdout */ + print_pop_error(ctx, stdout); + retval = -1; /* an error 'taints' the execution */ + } else { + duk_pop(ctx); + } + } + + if (buffer) { + linenoiseFree(buffer); + buffer = NULL; + } + + return retval; +} +#else /* DUK_CMDLINE_LINENOISE */ static int handle_interactive(duk_context *ctx) { const char *prompt = "duk> "; char *buffer = NULL; @@ -365,7 +759,7 @@ static int handle_interactive(duk_context *ctx) { int rc; int got_eof = 0; - duk_eval_string(ctx, GREET_CODE(" [no readline]")); + duk_eval_string(ctx, GREET_CODE("")); duk_pop(ctx); buffer = (char *) malloc(LINEBUF_SIZE); @@ -428,78 +822,172 @@ static int handle_interactive(duk_context *ctx) { return retval; } -#else /* NO_READLINE */ -static int handle_interactive(duk_context *ctx) { - const char *prompt = "duk> "; - char *buffer = NULL; - int retval = 0; +#endif /* DUK_CMDLINE_LINENOISE */ + +/* + * Simple file read/write bindings + */ + +#if defined(DUK_CMDLINE_FILEIO) +static duk_ret_t fileio_read_file(duk_context *ctx) { + const char *fn; + char *buf; + size_t len; + size_t off; int rc; + FILE *f; - duk_eval_string(ctx, GREET_CODE("")); - duk_pop(ctx); - - /* - * Note: using readline leads to valgrind-reported leaks inside - * readline itself. Execute code from an input file (and not - * through stdin) for clean valgrind runs. - */ - - rl_initialize(); - - for (;;) { - if (buffer) { - free(buffer); - buffer = NULL; - } - - buffer = readline(prompt); - if (!buffer) { - break; - } - - if (buffer && buffer[0] != (char) 0) { - add_history(buffer); - } - - duk_push_pointer(ctx, (void *) buffer); - duk_push_uint(ctx, (duk_uint_t) strlen(buffer)); - duk_push_string(ctx, "input"); - - interactive_mode = 1; /* global */ - - rc = duk_safe_call(ctx, wrapped_compile_execute, 3 /*nargs*/, 1 /*nret*/); - -#if defined(DUK_CMDLINE_AJSHEAP) - ajsheap_clear_exec_timeout(); -#endif - - if (buffer) { - free(buffer); - buffer = NULL; - } - - if (rc != DUK_EXEC_SUCCESS) { - /* in interactive mode, write to stdout */ - print_pop_error(ctx, stdout); - retval = -1; /* an error 'taints' the execution */ - } else { - duk_pop(ctx); - } + fn = duk_require_string(ctx, 0); + f = fopen(fn, "rb"); + if (!f) { + duk_error(ctx, DUK_ERR_TYPE_ERROR, "cannot open file %s for reading, errno %ld: %s", + fn, (long) errno, strerror(errno)); } - if (buffer) { - free(buffer); - buffer = NULL; + rc = fseek(f, 0, SEEK_END); + if (rc < 0) { + (void) fclose(f); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "fseek() failed for %s, errno %ld: %s", + fn, (long) errno, strerror(errno)); + } + len = (size_t) ftell(f); + rc = fseek(f, 0, SEEK_SET); + if (rc < 0) { + (void) fclose(f); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "fseek() failed for %s, errno %ld: %s", + fn, (long) errno, strerror(errno)); } - return retval; + buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) len); + for (off = 0; off < len;) { + size_t got; + got = fread((void *) (buf + off), 1, len - off, f); + if (ferror(f)) { + (void) fclose(f); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "error while reading %s", fn); + } + if (got == 0) { + if (feof(f)) { + break; + } else { + (void) fclose(f); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "error while reading %s", fn); + } + } + off += got; + } + + if (f) { + (void) fclose(f); + } + + return 1; +} + +static duk_ret_t fileio_write_file(duk_context *ctx) { + const char *fn; + const char *buf; + size_t len; + size_t off; + FILE *f; + + fn = duk_require_string(ctx, 0); + f = fopen(fn, "wb"); + if (!f) { + duk_error(ctx, DUK_ERR_TYPE_ERROR, "cannot open file %s for writing, errno %ld: %s", + fn, (long) errno, strerror(errno)); + } + + len = 0; + buf = (char *) duk_to_buffer(ctx, 1, &len); + for (off = 0; off < len;) { + size_t got; + got = fwrite((const void *) (buf + off), 1, len - off, f); + if (ferror(f)) { + (void) fclose(f); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "error while writing %s", fn); + } + if (got == 0) { + (void) fclose(f); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "error while writing %s", fn); + } + off += got; + } + + if (f) { + (void) fclose(f); + } + + return 0; +} +#endif /* DUK_CMDLINE_FILEIO */ + +/* + * Duktape heap lifecycle + */ + +#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) +static duk_idx_t debugger_request(duk_context *ctx, void *udata, duk_idx_t nvalues) { + const char *cmd; + int i; + + (void) udata; + + if (nvalues < 1) { + duk_push_string(ctx, "missing AppRequest argument(s)"); + return -1; + } + + cmd = duk_get_string(ctx, -nvalues + 0); + + if (cmd && strcmp(cmd, "CommandLine") == 0) { + if (!duk_check_stack(ctx, main_argc)) { + /* Callback should avoid errors for now, so use + * duk_check_stack() rather than duk_require_stack(). + */ + duk_push_string(ctx, "failed to extend stack"); + return -1; + } + for (i = 0; i < main_argc; i++) { + duk_push_string(ctx, main_argv[i]); + } + return main_argc; + } + duk_push_sprintf(ctx, "command not supported"); + return -1; } -#endif /* NO_READLINE */ -#ifdef DUK_CMDLINE_DEBUGGER_SUPPORT static void debugger_detached(void *udata) { + duk_context *ctx = (duk_context *) udata; + (void) ctx; fprintf(stderr, "Debugger detached, udata: %p\n", (void *) udata); fflush(stderr); + + /* Ensure socket is closed even when detach is initiated by Duktape + * rather than debug client. + */ + duk_trans_socket_finish(); + + if (debugger_reattach) { + /* For automatic reattach testing. */ + duk_trans_socket_init(); + duk_trans_socket_waitconn(); + fprintf(stderr, "Debugger reconnected, call duk_debugger_attach()\n"); + fflush(stderr); +#if 0 + /* This is not necessary but should be harmless. */ + duk_debugger_detach(ctx); +#endif + duk_debugger_attach_custom(ctx, + duk_trans_socket_read_cb, + duk_trans_socket_write_cb, + duk_trans_socket_peek_cb, + duk_trans_socket_read_flush_cb, + duk_trans_socket_write_flush_cb, + debugger_request, + debugger_detached, + (void *) ctx); + } } #endif @@ -509,12 +997,14 @@ static void debugger_detached(void *udata) { #define ALLOC_HYBRID 3 #define ALLOC_AJSHEAP 4 -static duk_context *create_duktape_heap(int alloc_provider, int debugger) { +static duk_context *create_duktape_heap(int alloc_provider, int debugger, int ajsheap_log) { duk_context *ctx; + (void) ajsheap_log; /* suppress warning */ + ctx = NULL; if (!ctx && alloc_provider == ALLOC_LOGGING) { -#ifdef DUK_CMDLINE_ALLOC_LOGGING +#if defined(DUK_CMDLINE_ALLOC_LOGGING) ctx = duk_create_heap(duk_alloc_logging, duk_realloc_logging, duk_free_logging, @@ -526,7 +1016,7 @@ static duk_context *create_duktape_heap(int alloc_provider, int debugger) { #endif } if (!ctx && alloc_provider == ALLOC_TORTURE) { -#ifdef DUK_CMDLINE_ALLOC_TORTURE +#if defined(DUK_CMDLINE_ALLOC_TORTURE) ctx = duk_create_heap(duk_alloc_torture, duk_realloc_torture, duk_free_torture, @@ -538,7 +1028,7 @@ static duk_context *create_duktape_heap(int alloc_provider, int debugger) { #endif } if (!ctx && alloc_provider == ALLOC_HYBRID) { -#ifdef DUK_CMDLINE_ALLOC_HYBRID +#if defined(DUK_CMDLINE_ALLOC_HYBRID) void *udata = duk_alloc_hybrid_init(); if (!udata) { fprintf(stderr, "Failed to init hybrid allocator\n"); @@ -556,7 +1046,7 @@ static duk_context *create_duktape_heap(int alloc_provider, int debugger) { #endif } if (!ctx && alloc_provider == ALLOC_AJSHEAP) { -#ifdef DUK_CMDLINE_AJSHEAP +#if defined(DUK_CMDLINE_AJSHEAP) ajsheap_init(); ctx = duk_create_heap( @@ -581,35 +1071,43 @@ static duk_context *create_duktape_heap(int alloc_provider, int debugger) { exit(-1); } -#ifdef DUK_CMDLINE_AJSHEAP +#if defined(DUK_CMDLINE_AJSHEAP) if (alloc_provider == ALLOC_AJSHEAP) { fprintf(stdout, "Pool dump after heap creation\n"); ajsheap_dump(); } #endif -#ifdef DUK_CMDLINE_AJSHEAP +#if defined(DUK_CMDLINE_AJSHEAP) if (alloc_provider == ALLOC_AJSHEAP) { ajsheap_register(ctx); } #endif +#if defined(DUK_CMDLINE_FILEIO) + duk_push_c_function(ctx, fileio_read_file, 1 /*nargs*/); + duk_put_global_string(ctx, "readFile"); + duk_push_c_function(ctx, fileio_write_file, 2 /*nargs*/); + duk_put_global_string(ctx, "writeFile"); +#endif + if (debugger) { -#ifdef DUK_CMDLINE_DEBUGGER_SUPPORT +#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) fprintf(stderr, "Debugger enabled, create socket and wait for connection\n"); fflush(stderr); duk_trans_socket_init(); duk_trans_socket_waitconn(); fprintf(stderr, "Debugger connected, call duk_debugger_attach() and then execute requested file(s)/eval\n"); fflush(stderr); - duk_debugger_attach(ctx, - duk_trans_socket_read_cb, - duk_trans_socket_write_cb, - duk_trans_socket_peek_cb, - duk_trans_socket_read_flush_cb, - duk_trans_socket_write_flush_cb, - debugger_detached, - (void *) 0xbeef1234); + duk_debugger_attach_custom(ctx, + duk_trans_socket_read_cb, + duk_trans_socket_write_cb, + duk_trans_socket_peek_cb, + duk_trans_socket_read_flush_cb, + duk_trans_socket_write_flush_cb, + debugger_request, + debugger_detached, + (void *) ctx); #else fprintf(stderr, "Warning: option --debugger ignored, no debugger support\n"); fflush(stderr); @@ -633,7 +1131,7 @@ static duk_context *create_duktape_heap(int alloc_provider, int debugger) { static void destroy_duktape_heap(duk_context *ctx, int alloc_provider) { (void) alloc_provider; -#ifdef DUK_CMDLINE_AJSHEAP +#if defined(DUK_CMDLINE_AJSHEAP) if (alloc_provider == ALLOC_AJSHEAP) { fprintf(stdout, "Pool dump before duk_destroy_heap(), before forced gc\n"); ajsheap_dump(); @@ -649,14 +1147,19 @@ static void destroy_duktape_heap(duk_context *ctx, int alloc_provider) { duk_destroy_heap(ctx); } -#ifdef DUK_CMDLINE_AJSHEAP +#if defined(DUK_CMDLINE_AJSHEAP) if (alloc_provider == ALLOC_AJSHEAP) { fprintf(stdout, "Pool dump after duk_destroy_heap() (should have zero allocs)\n"); ajsheap_dump(); } + ajsheap_free(); #endif } +/* + * Main + */ + int main(int argc, char *argv[]) { duk_context *ctx = NULL; int retval = 0; @@ -668,11 +1171,63 @@ int main(int argc, char *argv[]) { int ajsheap_log = 0; int debugger = 0; int recreate_heap = 0; + int no_heap_destroy = 0; int verbose = 0; + int run_stdin = 0; const char *compile_filename = NULL; int i; -#ifdef DUK_CMDLINE_AJSHEAP + main_argc = argc; + main_argv = (char **) argv; + +#if defined(EMSCRIPTEN) + /* Try to use NODEFS to provide access to local files. Mount the + * CWD as /working, and then prepend "/working/" to relative native + * paths in file calls to get something that works reasonably for + * relative paths. Emscripten doesn't support replacing virtual + * "/" with host "/" (the default MEMFS at "/" can't be unmounted) + * but we can mount "/tmp" as host "/tmp" to allow testcase runs. + * + * https://kripken.github.io/emscripten-site/docs/api_reference/Filesystem-API.html#filesystem-api-nodefs + * https://github.com/kripken/emscripten/blob/master/tests/fs/test_nodefs_rw.c + */ + EM_ASM( + /* At the moment it's not possible to replace the default MEMFS mounted at '/': + * https://github.com/kripken/emscripten/issues/2040 + * https://github.com/kripken/emscripten/blob/incoming/src/library_fs.js#L1341-L1358 + */ + /* + try { + FS.unmount("/"); + } catch (e) { + console.log("Failed to unmount default '/' MEMFS mount: " + e); + } + */ + try { + FS.mkdir("/working"); + FS.mount(NODEFS, { root: "." }, "/working"); + } catch (e) { + console.log("Failed to mount NODEFS /working: " + e); + } + /* A virtual '/tmp' exists by default: + * https://gist.github.com/evanw/e6be28094f34451bd5bd#file-temp-js-L3806-L3809 + */ + /* + try { + FS.mkdir("/tmp"); + } catch (e) { + console.log("Failed to create virtual /tmp: " + e); + } + */ + try { + FS.mount(NODEFS, { root: "/tmp" }, "/tmp"); + } catch (e) { + console.log("Failed to mount NODEFS /tmp: " + e); + } + ); +#endif /* EMSCRIPTEN */ + +#if defined(DUK_CMDLINE_AJSHEAP) alloc_provider = ALLOC_AJSHEAP; #endif (void) ajsheap_log; @@ -681,7 +1236,7 @@ int main(int argc, char *argv[]) { * Signal handling setup */ -#ifndef NO_SIGNAL +#if defined(DUK_CMDLINE_SIGNAL) set_sigint_handler(); /* This is useful at the global level; libraries should avoid SIGPIPE though */ @@ -727,17 +1282,25 @@ int main(int argc, char *argv[]) { ajsheap_log = 1; } else if (strcmp(arg, "--debugger") == 0) { debugger = 1; +#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) + } else if (strcmp(arg, "--reattach") == 0) { + debugger_reattach = 1; +#endif } else if (strcmp(arg, "--recreate-heap") == 0) { recreate_heap = 1; + } else if (strcmp(arg, "--no-heap-destroy") == 0) { + no_heap_destroy = 1; } else if (strcmp(arg, "--verbose") == 0) { verbose = 1; + } else if (strcmp(arg, "--run-stdin") == 0) { + run_stdin = 1; } else if (strlen(arg) >= 1 && arg[0] == '-') { goto usage; } else { have_files = 1; } } - if (!have_files && !have_eval) { + if (!have_files && !have_eval && !run_stdin) { interactive = 1; } @@ -745,7 +1308,7 @@ int main(int argc, char *argv[]) { * Memory limit */ -#ifndef NO_RLIMIT +#if defined(DUK_CMDLINE_RLIMIT) set_resource_limits(memlimit_high ? MEM_LIMIT_HIGH : MEM_LIMIT_NORMAL); #else if (memlimit_high == 0) { @@ -758,7 +1321,7 @@ int main(int argc, char *argv[]) { * Create heap */ - ctx = create_duktape_heap(alloc_provider, debugger); + ctx = create_duktape_heap(alloc_provider, debugger, ajsheap_log); /* * Execute any argument file(s) @@ -804,7 +1367,28 @@ int main(int argc, char *argv[]) { } destroy_duktape_heap(ctx, alloc_provider); - ctx = create_duktape_heap(alloc_provider, debugger); + ctx = create_duktape_heap(alloc_provider, debugger, ajsheap_log); + } + } + + if (run_stdin) { + /* Running stdin like a full file (reading all lines before + * compiling) is useful with emduk: + * cat test.js | ./emduk --run-stdin + */ + if (handle_fh(ctx, stdin, "stdin", compile_filename) != 0) { + retval = 1; + goto cleanup; + } + + if (recreate_heap) { + if (verbose) { + fprintf(stderr, "*** Recreating heap...\n"); + fflush(stderr); + } + + destroy_duktape_heap(ctx, alloc_provider); + ctx = create_duktape_heap(alloc_provider, debugger, ajsheap_log); } } @@ -829,7 +1413,10 @@ int main(int argc, char *argv[]) { fflush(stderr); } - if (ctx) { + if (ctx && no_heap_destroy) { + duk_gc(ctx, 0); + } + if (ctx && !no_heap_destroy) { destroy_duktape_heap(ctx, alloc_provider); } ctx = NULL; @@ -846,26 +1433,29 @@ int main(int argc, char *argv[]) { " -i enter interactive mode after executing argument file(s) / eval code\n" " -e CODE evaluate code\n" " -c FILE compile into bytecode (use with only one file argument)\n" + " --run-stdin treat stdin like a file, i.e. compile full input (not line by line)\n" " --verbose verbose messages to stderr\n" " --restrict-memory use lower memory limit (used by test runner)\n" " --alloc-default use Duktape default allocator\n" -#ifdef DUK_CMDLINE_ALLOC_LOGGING +#if defined(DUK_CMDLINE_ALLOC_LOGGING) " --alloc-logging use logging allocator (writes to /tmp)\n" #endif -#ifdef DUK_CMDLINE_ALLOC_TORTURE +#if defined(DUK_CMDLINE_ALLOC_TORTURE) " --alloc-torture use torture allocator\n" #endif -#ifdef DUK_CMDLINE_ALLOC_HYBRID +#if defined(DUK_CMDLINE_ALLOC_HYBRID) " --alloc-hybrid use hybrid allocator\n" #endif -#ifdef DUK_CMDLINE_AJSHEAP +#if defined(DUK_CMDLINE_AJSHEAP) " --alloc-ajsheap use ajsheap allocator (enabled by default with 'ajduk')\n" " --ajsheap-log write alloc log to /tmp/ajduk-alloc-log.txt\n" #endif -#ifdef DUK_CMDLINE_DEBUGGER_SUPPORT +#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) " --debugger start example debugger\n" + " --reattach automatically reattach debugger on detach\n" #endif " --recreate-heap recreate heap after every file\n" + " --no-heap-destroy force GC, but don't destroy heap at end (leak testing)\n" "\n" "If is omitted, interactive mode is started automatically.\n"); fflush(stderr); diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/cmdline/duk_cmdline_ajduk.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cmdline/duk_cmdline_ajduk.c similarity index 81% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/cmdline/duk_cmdline_ajduk.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cmdline/duk_cmdline_ajduk.c index c445fd441..ae28ede3f 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/cmdline/duk_cmdline_ajduk.c +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cmdline/duk_cmdline_ajduk.c @@ -10,13 +10,43 @@ #include #include "ajs.h" #include "ajs_heap.h" +#include "duktape.h" extern uint8_t dbgHEAPDUMP; +#if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16) +/* Pointer compression with ROM strings/objects: + * + * For now, use DUK_USE_ROM_OBJECTS to signal the need for compressed ROM + * pointers. DUK_USE_ROM_PTRCOMP_FIRST is provided for the ROM pointer + * compression range minimum to avoid duplication in user code. + */ +#if 0 /* This extern declaration is provided by duktape.h, array provided by duktape.c. */ +extern const void * const duk_rom_compressed_pointers[]; +#endif +static const void *duk__romptr_low = NULL; +static const void *duk__romptr_high = NULL; +#define DUK__ROMPTR_COMPRESSION +#define DUK__ROMPTR_FIRST DUK_USE_ROM_PTRCOMP_FIRST +#endif + /* * Helpers */ +static void *ajduk__lose_const(const void *ptr) { + /* Somewhat portable way of losing a const without warnings. + * Another approach is to cast through intptr_t, but that + * type is not always available. + */ + union { + const void *p; + void *q; + } u; + u.p = ptr; + return u.q; +} + static void safe_print_chars(const char *p, duk_size_t len, int until_nul) { duk_size_t i; @@ -53,13 +83,13 @@ static void safe_print_chars(const char *p, duk_size_t len, int until_nul) { static const AJS_HeapConfig ajsheap_config[] = { { 8, 10, AJS_POOL_BORROW, 0 }, - { 12, 10, AJS_POOL_BORROW, 0 }, - { 16, 200, AJS_POOL_BORROW, 0 }, - { 20, 400, AJS_POOL_BORROW, 0 }, - { 24, 400, AJS_POOL_BORROW, 0 }, - { 28, 200, AJS_POOL_BORROW, 0 }, - { 32, 200, AJS_POOL_BORROW, 0 }, - { 40, 200, AJS_POOL_BORROW, 0 }, + { 12, 600, AJS_POOL_BORROW, 0 }, + { 16, 300, AJS_POOL_BORROW, 0 }, + { 20, 300, AJS_POOL_BORROW, 0 }, + { 24, 300, AJS_POOL_BORROW, 0 }, + { 28, 150, AJS_POOL_BORROW, 0 }, + { 32, 150, AJS_POOL_BORROW, 0 }, + { 40, 150, AJS_POOL_BORROW, 0 }, { 48, 50, AJS_POOL_BORROW, 0 }, { 52, 50, AJS_POOL_BORROW, 0 }, { 56, 50, AJS_POOL_BORROW, 0 }, @@ -67,9 +97,12 @@ static const AJS_HeapConfig ajsheap_config[] = { { 64, 50, AJS_POOL_BORROW, 0 }, { 128, 80, AJS_POOL_BORROW, 0 }, { 256, 16, AJS_POOL_BORROW, 0 }, + { 320, 1, AJS_POOL_BORROW, 0 }, + { 392, 1, AJS_POOL_BORROW, 0 }, /* duk_hthread, with heap ptr compression, ROM strings+objects */ { 512, 16, AJS_POOL_BORROW, 0 }, + { 964, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, ROM strings+objects */ { 1024, 6, AJS_POOL_BORROW, 0 }, - { 1360, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression */ + { 1344, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, RAM strings+objects */ { 2048, 5, AJS_POOL_BORROW, 0 }, { 4096, 3, 0, 0 }, { 8192, 3, 0, 0 }, @@ -116,6 +149,35 @@ void ajsheap_init(void) { /* Enable heap dumps */ dbgHEAPDUMP = 1; + +#if defined(DUK__ROMPTR_COMPRESSION) + /* Scan ROM pointer range for faster detection of "is 'p' a ROM pointer" + * later on. + */ + if (1) { + const void * const * ptrs = (const void * const *) duk_rom_compressed_pointers; + duk__romptr_low = duk__romptr_high = (const void *) *ptrs; + while (*ptrs) { + if (*ptrs > duk__romptr_high) { + duk__romptr_high = (const void *) *ptrs; + } + if (*ptrs < duk__romptr_low) { + duk__romptr_low = (const void *) *ptrs; + } + ptrs++; + } + fprintf(stderr, "romptrs: low=%p high=%p\n", + (const void *) duk__romptr_low, (const void *) duk__romptr_high); + fflush(stderr); + } +#endif +} + +void ajsheap_free(void) { + if (ajsheap_ram != NULL) { + free(ajsheap_ram); + ajsheap_ram = NULL; + } } /* AjsHeap.dump(), allows Ecmascript code to dump heap status at suitable @@ -224,6 +286,37 @@ duk_uint16_t ajsheap_enc16(void *ud, void *p) { duk_uint32_t ret; char *base = (char *) ajsheap_ram - 4; +#if defined(DUK__ROMPTR_COMPRESSION) + if (p >= duk__romptr_low && p <= duk__romptr_high) { + /* The if-condition should be the fastest possible check + * for "is 'p' in ROM?". If pointer is in ROM, we'd like + * to compress it quickly. Here we just scan a ~1K array + * which is very bad for performance and for illustration + * only. + */ + const void * const * ptrs = duk_rom_compressed_pointers; + while (*ptrs) { + if (*ptrs == p) { + ret = DUK__ROMPTR_FIRST + (ptrs - duk_rom_compressed_pointers); +#if 0 + fprintf(stderr, "ajsheap_enc16: rom pointer: %p -> 0x%04lx\n", (void *) p, (long) ret); + fflush(stderr); +#endif + return (duk_uint16_t) ret; + } + ptrs++; + } + + /* We should really never be here: Duktape should only be + * compressing pointers which are in the ROM compressed + * pointers list, which are known at 'make dist' time. + * We go on, causing a pointer compression error. + */ + fprintf(stderr, "ajsheap_enc16: rom pointer: %p could not be compressed, should never happen\n", (void *) p); + fflush(stderr); + } +#endif + /* Userdata is not needed in this case but would be useful if heap * pointer compression were used for multiple heaps. The userdata * allows the callback to distinguish between heaps and their base @@ -254,16 +347,39 @@ duk_uint16_t ajsheap_enc16(void *ud, void *p) { printf("ajsheap_enc16: %p -> %u\n", p, (unsigned int) ret); #endif if (ret > 0xffffUL) { - fprintf(stderr, "Failed to compress pointer\n"); + fprintf(stderr, "Failed to compress pointer: %p (ret was %ld)\n", (void *) p, (long) ret); fflush(stderr); abort(); } +#if defined(DUK__ROMPTR_COMPRESSION) + if (ret >= DUK__ROMPTR_FIRST) { + fprintf(stderr, "Failed to compress pointer, in 16-bit range but matches romptr range: %p (ret was %ld)\n", (void *) p, (long) ret); + fflush(stderr); + abort(); + } +#endif return (duk_uint16_t) ret; } + void *ajsheap_dec16(void *ud, duk_uint16_t x) { void *ret; char *base = (char *) ajsheap_ram - 4; +#if defined(DUK__ROMPTR_COMPRESSION) + if (x >= DUK__ROMPTR_FIRST) { + /* This is a blind lookup, could check index validity. + * Duktape should never decompress a pointer which would + * be out-of-bounds here. + */ + ret = (void *) ajduk__lose_const(duk_rom_compressed_pointers[x - DUK__ROMPTR_FIRST]); +#if 0 + fprintf(stderr, "ajsheap_dec16: rom pointer: 0x%04lx -> %p\n", (long) x, ret); + fflush(stderr); +#endif + return ret; + } +#endif + /* See userdata discussion in ajsheap_enc16(). */ (void) ud; #if 1 @@ -777,7 +893,7 @@ const void *ajsheap_extstr_check_2(const void *ptr, duk_size_t len) { safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); printf(" -> constant string index %ld\n", (long) i); #endif - return (void *) strdata_duk_builtin_strings[i]; + return (void *) ajduk__lose_const(strdata_duk_builtin_strings[i]); } } @@ -842,7 +958,7 @@ void ajsheap_extstr_free_3(const void *ptr) { safe_print_chars((const char *) ptr, DUK_SIZE_MAX, 1 /*until_nul*/); printf("\n"); #endif - free((void *) ptr); + free((void *) ajduk__lose_const(ptr)); } /* diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/codepage-conv/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/codepage-conv/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/codepage-conv/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/codepage-conv/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/codepage-conv/duk_codepage_conv.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/codepage-conv/duk_codepage_conv.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/codepage-conv/duk_codepage_conv.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/codepage-conv/duk_codepage_conv.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/codepage-conv/duk_codepage_conv.h b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/codepage-conv/duk_codepage_conv.h similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/codepage-conv/duk_codepage_conv.h rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/codepage-conv/duk_codepage_conv.h diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/codepage-conv/test.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/codepage-conv/test.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/codepage-conv/test.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/codepage-conv/test.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/coffee/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/coffee/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/coffee/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/coffee/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/coffee/globals.coffee b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/coffee/globals.coffee similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/coffee/globals.coffee rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/coffee/globals.coffee diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/coffee/hello.coffee b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/coffee/hello.coffee similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/coffee/hello.coffee rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/coffee/hello.coffee diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/coffee/mandel.coffee b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/coffee/mandel.coffee similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/coffee/mandel.coffee rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/coffee/mandel.coffee diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cpp-exceptions/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cpp-exceptions/README.rst new file mode 100644 index 000000000..bbc26a037 --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cpp-exceptions/README.rst @@ -0,0 +1,29 @@ +========================================= +C++ exceptions for long control transfers +========================================= + +Normally Duktape uses ``setjmp()`` / ``longjmp()`` or their variants for +internal long control transfers. One downside of these functions is that +C++ automatic destructors (scope-based resource management, SBRM, a special +case of RAII) in Duktape/C functions won't be executed which is awkward for +C++ programmers. + +When ``DUK_USE_CPP_EXCEPTIONS`` (``DUK_OPT_CPP_EXCEPTIONS``) is defined, and +both Duktape and application code is compiled using a C++ compiler, Duktape +uses C++ ``try-catch`` and ``throw`` for internal long control transfers. +This allows automatic destructors to run as expected. The config option is +not enabled by default because C++ exceptions are sometimes disabled even +when a C++ compiler is used (e.g. for performance reasons). + +The ``cpp_exceptions.cpp`` example illustrates how C++ exceptions can be +used in Duktape/C functions at the moment: + +* Duktape uses C++ try/catch/throw internally; this is not visible to user + code directly. + +* Automatic destructors (scope-based resource management) work as expected. + +* C++ exceptions can be used in Duktape/C functions normally, but user + exceptions must be caught before they reach Duktape. If this is not + done, such exceptions are caught by Duktape and converted to API errors + (in other words, they won't propagate "through" Duktape at the moment). diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cpp-exceptions/cpp_exceptions.cpp b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cpp-exceptions/cpp_exceptions.cpp new file mode 100644 index 000000000..6fb3194da --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/cpp-exceptions/cpp_exceptions.cpp @@ -0,0 +1,274 @@ +/* + * Example of how to use DUK_USE_CPP_EXCEPTIONS to support automatic + * variables (e.g. destructor calls) in Duktape/C functions. + * + * Compile with -DDUK_OPT_CPP_EXCEPTIONS: + * + * $ g++ -otest -DDUK_OPT_CPP_EXCEPTIONS -I/src/ \ + * /src/duktape.c cpp_exceptions.cpp -lm + * + * or ensure duk_config.h has DUK_USE_CPP_EXCEPTIONS enabled using + * genconfig. When executed you should see something like: + * + * $ ./test + * my_class instance created + * my_class instance destroyed <== destructor gets called + * --> rc=1 (SyntaxError: parse error (line 1)) + * [...] + * + * Duktape uses a custom exception class (duk_internal_exception) which + * doesn't inherit from any base class, so that catching any base classes + * in user code won't accidentally catch exceptions thrown by Duktape. + */ + +#if !defined(__cplusplus) +#error compile using a c++ compiler +#endif + +#include +#include +#include "duktape.h" + +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define NOEXCEPT noexcept +#else +#define NOEXCEPT throw() +#endif + +/* + * Example class with a destructor + */ + +class my_class { + public: + my_class(); + ~my_class(); +}; + +my_class::my_class() { + printf("my_class instance created\n"); +} + +my_class::~my_class() { + printf("my_class instance destroyed\n"); +} + +/* + * SyntaxError caused by eval exits Duktape/C function but destructors + * are executed. + */ + +duk_ret_t test1(duk_context *ctx) { + my_class myclass; + + duk_eval_string(ctx, "aiee="); + + return 0; +} + +/* + * You can use C++ exceptions inside Duktape/C functions for your own + * purposes but you should catch them before they propagate to Duktape. + */ + +duk_ret_t test2(duk_context *ctx) { + my_class myclass; + + try { + throw 123; + } catch (int myvalue) { + printf("Caught: %d\n", myvalue); + } + + return 0; +} + +/* + * If you let your own C++ exceptions propagate out of a Duktape/C function + * it will be caught by Duktape and considered a programming error. Duktape + * will catch the exception and convert it to a Duktape error. + * + * This may be allowed in a later version once all the implications have been + * worked out. + */ + +duk_ret_t test3(duk_context *ctx) { + my_class myclass; + + throw 123; /* ERROR: exception propagated to Duktape */ + + return 0; +} + +/* + * Same as above, but if the exception inherits from std::exception, it's + * "what()" will be included in the error message. + */ + +class my_exception : public std::exception { + virtual const char *what() const NOEXCEPT { + return "my_exception"; + } +}; + +duk_ret_t test4(duk_context *ctx) { + my_class myclass; + my_exception myexc; + + throw myexc; /* ERROR: exception propagated to Duktape */ + + return 0; +} + +/* + * Same as above, but if the exception inherits from std::exception with + * a NULL what(). Duktape will describe the error as 'unknown' if so. + */ + +class my_exception2 : public std::exception { + virtual const char *what() const NOEXCEPT { + return NULL; + } +}; + +duk_ret_t test5(duk_context *ctx) { + my_class myclass; + my_exception2 myexc; + + throw myexc; /* ERROR: exception propagated to Duktape */ + + return 0; +} + +int main(int argc, char *argv[]) { + duk_context *ctx = duk_create_heap_default(); + duk_int_t rc; + + (void) argc; (void) argv; /* suppress warning */ + + printf("*** test1 - duk_pcall()\n"); + duk_push_c_function(ctx, test1, 0); + rc = duk_pcall(ctx, 0); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test1 - duk_safe_call()\n"); + rc = duk_safe_call(ctx, test1, 0, 1); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test1 - ecmascript try-catch\n"); + duk_push_c_function(ctx, test1, 0); + duk_put_global_string(ctx, "test1"); + duk_eval_string_noresult(ctx, + "try {\n" + " test1();\n" + "} catch (e) {\n" + " print(e.stack || e);\n" + "}\n"); + printf("\n"); + + printf("*** test2 - duk_pcall()\n"); + duk_push_c_function(ctx, test2, 0); + rc = duk_pcall(ctx, 0); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test2 - duk_safe_call()\n"); + rc = duk_safe_call(ctx, test2, 0, 1); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test2 - ecmascript try-catch\n"); + duk_push_c_function(ctx, test2, 0); + duk_put_global_string(ctx, "test2"); + duk_eval_string_noresult(ctx, + "try {\n" + " test2();\n" + "} catch (e) {\n" + " print(e.stack || e);\n" + "}\n"); + printf("\n"); + + printf("*** test3 - duk_pcall()\n"); + duk_push_c_function(ctx, test3, 0); + rc = duk_pcall(ctx, 0); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test3 - duk_safe_call()\n"); + rc = duk_safe_call(ctx, test3, 0, 1); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test3 - ecmascript try-catch\n"); + duk_push_c_function(ctx, test3, 0); + duk_put_global_string(ctx, "test3"); + duk_eval_string_noresult(ctx, + "try {\n" + " test3();\n" + "} catch (e) {\n" + " print(e.stack || e);\n" + "}\n"); + printf("\n"); + + printf("*** test4 - duk_pcall()\n"); + duk_push_c_function(ctx, test4, 0); + rc = duk_pcall(ctx, 0); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test4 - duk_safe_call()\n"); + rc = duk_safe_call(ctx, test4, 0, 1); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test4 - ecmascript try-catch\n"); + duk_push_c_function(ctx, test4, 0); + duk_put_global_string(ctx, "test4"); + duk_eval_string_noresult(ctx, + "try {\n" + " test4();\n" + "} catch (e) {\n" + " print(e.stack || e);\n" + "}\n"); + printf("\n"); + + printf("*** test5 - duk_pcall()\n"); + duk_push_c_function(ctx, test5, 0); + rc = duk_pcall(ctx, 0); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test5 - duk_safe_call()\n"); + rc = duk_safe_call(ctx, test5, 0, 1); + printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + printf("\n"); + + printf("*** test5 - ecmascript try-catch\n"); + duk_push_c_function(ctx, test5, 0); + duk_put_global_string(ctx, "test5"); + duk_eval_string_noresult(ctx, + "try {\n" + " test5();\n" + "} catch (e) {\n" + " print(e.stack || e);\n" + "}\n"); + printf("\n"); + + printf("*** done\n"); + + duk_destroy_heap(ctx); + + return 0; +} diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/Makefile b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/Makefile similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/Makefile rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/Makefile diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/duk_trans_dvalue.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/duk_trans_dvalue.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/duk_trans_dvalue.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/duk_trans_dvalue.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/duk_trans_dvalue.h b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/duk_trans_dvalue.h similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/duk_trans_dvalue.h rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/duk_trans_dvalue.h diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/test.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/test.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-dvalue/test.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/test.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/README.rst new file mode 100644 index 000000000..78522cddb --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/README.rst @@ -0,0 +1,17 @@ +================================================ +Debug transport using a simple socket connection +================================================ + +This example implements an example debug transport which uses a Linux or +Windows TCP server socket on the debug target. + +Files: + +* ``duk_trans_socket.h``: header file for the transport, used for both Linux + and Windows socket variants. + +* ``duk_trans_socket_unix.c``: implementation for Linux/Unix. + +* ``duk_trans_socket_windows.c``: implementation for Windows. + +Compile either Unix or Windows source file only. diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-socket/duk_trans_socket.h b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket.h similarity index 93% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-socket/duk_trans_socket.h rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket.h index 60712a2e7..43f4a34de 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-socket/duk_trans_socket.h +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket.h @@ -4,6 +4,7 @@ #include "duktape.h" void duk_trans_socket_init(void); +void duk_trans_socket_finish(void); void duk_trans_socket_waitconn(void); duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length); duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t length); diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-socket/duk_trans_socket.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_unix.c similarity index 81% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-socket/duk_trans_socket.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_unix.c index c25fa3ea8..ac74de2bf 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-socket/duk_trans_socket.c +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_unix.c @@ -1,23 +1,20 @@ /* - * Example debug transport using a TCP socket + * Example debug transport using a Linux/Unix TCP socket * - * The application has a server socket which can be connected to. + * Provides a TCP server socket which a debug client can connect to. * After that data is just passed through. - * - * NOTE: This is Linux specific on purpose, as it's just an example how - * a debug transport can be concretely implemented. */ #include #include #include -#include +#include #include #include #include #include "duktape.h" -#ifndef DUK_DEBUG_PORT +#if !defined(DUK_DEBUG_PORT) #define DUK_DEBUG_PORT 9091 #endif @@ -29,7 +26,7 @@ static int server_sock = -1; static int client_sock = -1; /* - * Transport init + * Transport init and finish */ void duk_trans_socket_init(void) { @@ -38,14 +35,16 @@ void duk_trans_socket_init(void) { server_sock = socket(AF_INET, SOCK_STREAM, 0); if (server_sock < 0) { - fprintf(stderr, "%s: failed to create server socket: %s\n", __FILE__, strerror(errno)); + fprintf(stderr, "%s: failed to create server socket: %s\n", + __FILE__, strerror(errno)); fflush(stderr); goto fail; } on = 1; if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)) < 0) { - fprintf(stderr, "%s: failed to set SO_REUSEADDR for server socket: %s\n", __FILE__, strerror(errno)); + fprintf(stderr, "%s: failed to set SO_REUSEADDR for server socket: %s\n", + __FILE__, strerror(errno)); fflush(stderr); goto fail; } @@ -56,7 +55,8 @@ void duk_trans_socket_init(void) { addr.sin_port = htons(DUK_DEBUG_PORT); if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - fprintf(stderr, "%s: failed to bind server socket: %s\n", __FILE__, strerror(errno)); + fprintf(stderr, "%s: failed to bind server socket: %s\n", + __FILE__, strerror(errno)); fflush(stderr); goto fail; } @@ -71,12 +71,24 @@ void duk_trans_socket_init(void) { } } +void duk_trans_socket_finish(void) { + if (client_sock >= 0) { + (void) close(client_sock); + client_sock = -1; + } + if (server_sock >= 0) { + (void) close(server_sock); + server_sock = -1; + } +} + void duk_trans_socket_waitconn(void) { struct sockaddr_in addr; socklen_t sz; if (server_sock < 0) { - fprintf(stderr, "%s: no server socket, skip waiting for connection\n", __FILE__); + fprintf(stderr, "%s: no server socket, skip waiting for connection\n", + __FILE__); fflush(stderr); return; } @@ -91,7 +103,8 @@ void duk_trans_socket_waitconn(void) { sz = (socklen_t) sizeof(addr); client_sock = accept(server_sock, (struct sockaddr *) &addr, &sz); if (client_sock < 0) { - fprintf(stderr, "%s: accept() failed, skip waiting for connection: %s\n", __FILE__, strerror(errno)); + fprintf(stderr, "%s: accept() failed, skip waiting for connection: %s\n", + __FILE__, strerror(errno)); fflush(stderr); goto fail; } @@ -121,7 +134,7 @@ void duk_trans_socket_waitconn(void) { * Duktape callbacks */ -/* Duktape debug transport callback: partial read */ +/* Duktape debug transport callback: (possibly partial) read. */ duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length) { ssize_t ret; @@ -139,14 +152,16 @@ duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length if (length == 0) { /* This shouldn't happen. */ - fprintf(stderr, "%s: read request length == 0, closing connection\n", __FILE__); + fprintf(stderr, "%s: read request length == 0, closing connection\n", + __FILE__); fflush(stderr); goto fail; } if (buffer == NULL) { /* This shouldn't happen. */ - fprintf(stderr, "%s: read request buffer == NULL, closing connection\n", __FILE__); + fprintf(stderr, "%s: read request buffer == NULL, closing connection\n", + __FILE__); fflush(stderr); goto fail; } @@ -157,15 +172,18 @@ duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length ret = read(client_sock, (void *) buffer, (size_t) length); if (ret < 0) { - fprintf(stderr, "%s: debug read failed, errno %d, closing connection: %s\n", __FILE__, errno, strerror(errno)); + fprintf(stderr, "%s: debug read failed, closing connection: %s\n", + __FILE__, strerror(errno)); fflush(stderr); goto fail; } else if (ret == 0) { - fprintf(stderr, "%s: debug read failed, ret == 0 (EOF), closing connection\n", __FILE__); + fprintf(stderr, "%s: debug read failed, ret == 0 (EOF), closing connection\n", + __FILE__); fflush(stderr); goto fail; } else if (ret > (ssize_t) length) { - fprintf(stderr, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n", __FILE__, (long) ret, (long) length); + fprintf(stderr, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n", + __FILE__, (long) ret, (long) length); fflush(stderr); goto fail; } @@ -180,7 +198,7 @@ duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length return 0; } -/* Duktape debug transport callback: partial write */ +/* Duktape debug transport callback: (possibly partial) write. */ duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t length) { ssize_t ret; @@ -188,7 +206,7 @@ duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t #if defined(DEBUG_PRINTS) fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n", - __func__, (void *) udata, (void *) buffer, (long) length); + __func__, (void *) udata, (const void *) buffer, (long) length); fflush(stderr); #endif @@ -198,14 +216,16 @@ duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t if (length == 0) { /* This shouldn't happen. */ - fprintf(stderr, "%s: write request length == 0, closing connection\n", __FILE__); + fprintf(stderr, "%s: write request length == 0, closing connection\n", + __FILE__); fflush(stderr); goto fail; } if (buffer == NULL) { /* This shouldn't happen. */ - fprintf(stderr, "%s: write request buffer == NULL, closing connection\n", __FILE__); + fprintf(stderr, "%s: write request buffer == NULL, closing connection\n", + __FILE__); fflush(stderr); goto fail; } @@ -216,7 +236,8 @@ duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t ret = write(client_sock, (const void *) buffer, (size_t) length); if (ret <= 0 || ret > (ssize_t) length) { - fprintf(stderr, "%s: debug write failed, closing connection: %s\n", __FILE__, strerror(errno)); + fprintf(stderr, "%s: debug write failed, closing connection: %s\n", + __FILE__, strerror(errno)); fflush(stderr); goto fail; } @@ -242,17 +263,23 @@ duk_size_t duk_trans_socket_peek_cb(void *udata) { fflush(stderr); #endif + if (client_sock < 0) { + return 0; + } + fds[0].fd = client_sock; fds[0].events = POLLIN; fds[0].revents = 0; poll_rc = poll(fds, 1, 0); if (poll_rc < 0) { - fprintf(stderr, "%s: poll returned < 0, closing connection: %s\n", __FILE__, strerror(errno)); + fprintf(stderr, "%s: poll returned < 0, closing connection: %s\n", + __FILE__, strerror(errno)); fflush(stderr); goto fail; /* also returns 0, which is correct */ } else if (poll_rc > 1) { - fprintf(stderr, "%s: poll returned > 1, treating like 1\n", __FILE__); + fprintf(stderr, "%s: poll returned > 1, treating like 1\n", + __FILE__); fflush(stderr); return 1; /* should never happen */ } else if (poll_rc == 0) { @@ -270,13 +297,13 @@ duk_size_t duk_trans_socket_peek_cb(void *udata) { } void duk_trans_socket_read_flush_cb(void *udata) { + (void) udata; /* not needed by the example */ + #if defined(DEBUG_PRINTS) fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata); fflush(stderr); #endif - (void) udata; /* not needed by the example */ - /* Read flush: Duktape may not be making any more read calls at this * time. If the transport maintains a receive window, it can use a * read flush as a signal to update the window status to the remote @@ -292,13 +319,13 @@ void duk_trans_socket_read_flush_cb(void *udata) { } void duk_trans_socket_write_flush_cb(void *udata) { + (void) udata; /* not needed by the example */ + #if defined(DEBUG_PRINTS) fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata); fflush(stderr); #endif - (void) udata; /* not needed by the example */ - /* Write flush. If the transport combines multiple writes * before actually sending, a write flush is an indication * to write out any pending bytes: Duktape may not be doing diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_windows.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_windows.c new file mode 100644 index 000000000..e92ac2660 --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_windows.c @@ -0,0 +1,414 @@ +/* + * Example debug transport using a Windows TCP socket + * + * Provides a TCP server socket which a debug client can connect to. + * After that data is just passed through. + * + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx + * + * Compiling 'duk' with debugger support using MSVC (Visual Studio): + * + * > cl /W3 /O2 /Feduk.exe + * /DDUK_OPT_DEBUGGER_SUPPORT /DDUK_OPT_INTERRUPT_COUNTER + * /DDUK_CMDLINE_DEBUGGER_SUPPORT + * /Iexamples\debug-trans-socket /Isrc + * examples\cmdline\duk_cmdline.c + * examples\debug-trans-socket\duk_trans_socket_windows.c + * src\duktape.c + * + * With MinGW: + * + * $ gcc -oduk.exe -Wall -O2 \ + * -DDUK_OPT_DEBUGGER_SUPPORT -DDUK_OPT_INTERRUPT_COUNTER \ + * -DDUK_CMDLINE_DEBUGGER_SUPPORT \ + * -Iexamples/debug-trans-socket -Isrc \ + * examples/cmdline/duk_cmdline.c \ + * examples/debug-trans-socket/duk_trans_socket_windows.c \ + * src/duktape.c -lm -lws2_32 + */ + +#undef UNICODE +#if !defined(WIN32_LEAN_AND_MEAN) +#define WIN32_LEAN_AND_MEAN +#endif + +/* MinGW workaround for missing getaddrinfo() etc: + * http://programmingrants.blogspot.fi/2009/09/tips-on-undefined-reference-to.html + */ +#if defined(__MINGW32__) || defined(__MINGW64__) +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0501 +#endif +#endif + +#include +#include +#include +#include +#include +#include "duktape.h" + +#if defined(_MSC_VER) +#pragma comment (lib, "Ws2_32.lib") +#endif + +#if !defined(DUK_DEBUG_PORT) +#define DUK_DEBUG_PORT 9091 +#endif +#if !defined(DUK_DEBUG_ADDRESS) +#define DUK_DEBUG_ADDRESS "0.0.0.0" +#endif +#define DUK__STRINGIFY_HELPER(x) #x +#define DUK__STRINGIFY(x) DUK__STRINGIFY_HELPER(x) + +#if 0 +#define DEBUG_PRINTS +#endif + +static SOCKET server_sock = INVALID_SOCKET; +static SOCKET client_sock = INVALID_SOCKET; +static int wsa_inited = 0; + +/* + * Transport init and finish + */ + +void duk_trans_socket_init(void) { + WSADATA wsa_data; + struct addrinfo hints; + struct addrinfo *result = NULL; + int rc; + + memset((void *) &wsa_data, 0, sizeof(wsa_data)); + memset((void *) &hints, 0, sizeof(hints)); + + rc = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (rc != 0) { + fprintf(stderr, "%s: WSAStartup() failed: %d\n", __FILE__, rc); + fflush(stderr); + goto fail; + } + wsa_inited = 1; + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE; + + rc = getaddrinfo(DUK_DEBUG_ADDRESS, DUK__STRINGIFY(DUK_DEBUG_PORT), &hints, &result); + if (rc != 0) { + fprintf(stderr, "%s: getaddrinfo() failed: %d\n", __FILE__, rc); + fflush(stderr); + goto fail; + } + + server_sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + if (server_sock == INVALID_SOCKET) { + fprintf(stderr, "%s: socket() failed with error: %ld\n", + __FILE__, (long) WSAGetLastError()); + fflush(stderr); + goto fail; + } + + rc = bind(server_sock, result->ai_addr, (int) result->ai_addrlen); + if (rc == SOCKET_ERROR) { + fprintf(stderr, "%s: bind() failed with error: %ld\n", + __FILE__, (long) WSAGetLastError()); + fflush(stderr); + goto fail; + } + + rc = listen(server_sock, SOMAXCONN); + if (rc == SOCKET_ERROR) { + fprintf(stderr, "%s: listen() failed with error: %ld\n", + __FILE__, (long) WSAGetLastError()); + fflush(stderr); + goto fail; + } + + if (result != NULL) { + freeaddrinfo(result); + result = NULL; + } + return; + + fail: + if (result != NULL) { + freeaddrinfo(result); + result = NULL; + } + if (server_sock != INVALID_SOCKET) { + (void) closesocket(server_sock); + server_sock = INVALID_SOCKET; + } + if (wsa_inited) { + WSACleanup(); + wsa_inited = 0; + } +} + +void duk_trans_socket_finish(void) { + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } + if (server_sock != INVALID_SOCKET) { + (void) closesocket(server_sock); + server_sock = INVALID_SOCKET; + } + if (wsa_inited) { + WSACleanup(); + wsa_inited = 0; + } +} + +void duk_trans_socket_waitconn(void) { + if (server_sock == INVALID_SOCKET) { + fprintf(stderr, "%s: no server socket, skip waiting for connection\n", + __FILE__); + fflush(stderr); + return; + } + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } + + fprintf(stderr, "Waiting for debug connection on port %d\n", (int) DUK_DEBUG_PORT); + fflush(stderr); + + client_sock = accept(server_sock, NULL, NULL); + if (client_sock == INVALID_SOCKET) { + fprintf(stderr, "%s: accept() failed with error %ld, skip waiting for connection\n", + __FILE__, (long) WSAGetLastError()); + fflush(stderr); + goto fail; + } + + fprintf(stderr, "Debug connection established\n"); + fflush(stderr); + + /* XXX: For now, close the listen socket because we won't accept new + * connections anyway. A better implementation would allow multiple + * debug attaches. + */ + + if (server_sock != INVALID_SOCKET) { + (void) closesocket(server_sock); + server_sock = INVALID_SOCKET; + } + return; + + fail: + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } +} + +/* + * Duktape callbacks + */ + +/* Duktape debug transport callback: (possibly partial) read. */ +duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length) { + int ret; + + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n", + __FUNCTION__, (void *) udata, (void *) buffer, (long) length); + fflush(stderr); +#endif + + if (client_sock == INVALID_SOCKET) { + return 0; + } + + if (length == 0) { + /* This shouldn't happen. */ + fprintf(stderr, "%s: read request length == 0, closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } + + if (buffer == NULL) { + /* This shouldn't happen. */ + fprintf(stderr, "%s: read request buffer == NULL, closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } + + /* In a production quality implementation there would be a sanity + * timeout here to recover from "black hole" disconnects. + */ + + ret = recv(client_sock, (void *) buffer, (int) length, 0); + if (ret < 0) { + fprintf(stderr, "%s: debug read failed, error %d, closing connection\n", + __FILE__, ret); + fflush(stderr); + goto fail; + } else if (ret == 0) { + fprintf(stderr, "%s: debug read failed, ret == 0 (EOF), closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } else if (ret > (int) length) { + fprintf(stderr, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n", + __FILE__, (long) ret, (long) length); + fflush(stderr); + goto fail; + } + + return (duk_size_t) ret; + + fail: + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } + return 0; +} + +/* Duktape debug transport callback: (possibly partial) write. */ +duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t length) { + int ret; + + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n", + __FUNCTION__, (void *) udata, (const void *) buffer, (long) length); + fflush(stderr); +#endif + + if (client_sock == INVALID_SOCKET) { + return 0; + } + + if (length == 0) { + /* This shouldn't happen. */ + fprintf(stderr, "%s: write request length == 0, closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } + + if (buffer == NULL) { + /* This shouldn't happen. */ + fprintf(stderr, "%s: write request buffer == NULL, closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } + + /* In a production quality implementation there would be a sanity + * timeout here to recover from "black hole" disconnects. + */ + + ret = send(client_sock, (const void *) buffer, (int) length, 0); + if (ret <= 0 || ret > (int) length) { + fprintf(stderr, "%s: debug write failed, ret %d, closing connection\n", + __FILE__, ret); + fflush(stderr); + goto fail; + } + + return (duk_size_t) ret; + + fail: + if (client_sock != INVALID_SOCKET) { + (void) closesocket(INVALID_SOCKET); + client_sock = INVALID_SOCKET; + } + return 0; +} + +duk_size_t duk_trans_socket_peek_cb(void *udata) { + u_long avail; + int rc; + + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p\n", __FUNCTION__, (void *) udata); + fflush(stderr); +#endif + + if (client_sock == INVALID_SOCKET) { + return 0; + } + + avail = 0; + rc = ioctlsocket(client_sock, FIONREAD, &avail); + if (rc != 0) { + fprintf(stderr, "%s: ioctlsocket() returned %d, closing connection\n", + __FILE__, rc); + fflush(stderr); + goto fail; /* also returns 0, which is correct */ + } else { + if (avail == 0) { + return 0; /* nothing to read */ + } else { + return 1; /* something to read */ + } + } + /* never here */ + + fail: + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } + return 0; +} + +void duk_trans_socket_read_flush_cb(void *udata) { + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p\n", __FUNCTION__, (void *) udata); + fflush(stderr); +#endif + + /* Read flush: Duktape may not be making any more read calls at this + * time. If the transport maintains a receive window, it can use a + * read flush as a signal to update the window status to the remote + * peer. A read flush is guaranteed to occur before Duktape stops + * reading for a while; it may occur in other situations as well so + * it's not a 100% reliable indication. + */ + + /* This TCP transport requires no read flush handling so ignore. + * You can also pass a NULL to duk_debugger_attach() and not + * implement this callback at all. + */ +} + +void duk_trans_socket_write_flush_cb(void *udata) { + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p\n", __FUNCTION__, (void *) udata); + fflush(stderr); +#endif + + /* Write flush. If the transport combines multiple writes + * before actually sending, a write flush is an indication + * to write out any pending bytes: Duktape may not be doing + * any more writes on this occasion. + */ + + /* This TCP transport requires no write flush handling so ignore. + * You can also pass a NULL to duk_debugger_attach() and not + * implement this callback at all. + */ + return; +} + +#undef DUK__STRINGIFY_HELPER +#undef DUK__STRINGIFY diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/dummy-date-provider/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/dummy-date-provider/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/dummy-date-provider/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/dummy-date-provider/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/dummy-date-provider/dummy_date_provider.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/dummy-date-provider/dummy_date_provider.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/dummy-date-provider/dummy_date_provider.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/dummy-date-provider/dummy_date_provider.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eval/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eval/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eval/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eval/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eval/eval.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eval/eval.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eval/eval.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eval/eval.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/basic-test.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/basic-test.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/basic-test.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/basic-test.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/c_eventloop.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/c_eventloop.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/c_eventloop.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/c_eventloop.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/client-socket-test.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/client-socket-test.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/client-socket-test.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/client-socket-test.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/curses-timers.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/curses-timers.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/curses-timers.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/curses-timers.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/ecma_eventloop.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/ecma_eventloop.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/ecma_eventloop.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/ecma_eventloop.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/fileio.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/fileio.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/fileio.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/fileio.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/main.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/main.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/main.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/main.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/ncurses.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/ncurses.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/ncurses.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/ncurses.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/poll.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/poll.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/poll.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/poll.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/server-socket-test.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/server-socket-test.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/server-socket-test.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/server-socket-test.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/socket.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/socket.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/socket.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/eventloop/socket.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/fib.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/fib.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/fib.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/fib.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/prime.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/prime.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/prime.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/prime.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/primecheck.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/primecheck.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/primecheck.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/primecheck.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/process.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/process.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/process.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/process.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/processlines.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/processlines.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/processlines.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/processlines.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/uppercase.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/uppercase.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/guide/uppercase.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/guide/uppercase.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/hello/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/hello/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/hello/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/hello/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/hello/hello.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/hello/hello.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/hello/hello.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/hello/hello.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/jxpretty/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/jxpretty/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/jxpretty/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/jxpretty/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/jxpretty/jxpretty.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/jxpretty/jxpretty.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/jxpretty/jxpretty.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/jxpretty/jxpretty.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/sandbox/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/sandbox/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/sandbox/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/sandbox/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/sandbox/sandbox.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/sandbox/sandbox.c similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/sandbox/sandbox.c rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/sandbox/sandbox.c diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/extras/README.rst b/ceph/src/civetweb/src/third_party/duktape-1.5.2/extras/README.rst similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/extras/README.rst rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/extras/README.rst diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/license.spdx b/ceph/src/civetweb/src/third_party/duktape-1.5.2/license.spdx similarity index 61% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/license.spdx rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/license.spdx index 535d95f92..29a6b8de1 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/license.spdx +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/license.spdx @@ -4,3626 +4,3930 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" > - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/c_eventloop.js - <_3:checksum rdf:nodeID="NukVOfZA86"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/debug-trans-dvalue/duk_trans_dvalue.c - <_3:checksum rdf:nodeID="NukVOfZA160"/> - - - - <_3:checksumValue>215f6fec820889330048f7f2c1b5a220eb963657 + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hobject_misc.c - <_3:checksum rdf:nodeID="NukVOfZA192"/> - - + <_3:checksumValue>6f9134b7d1c939593043b9e0ecb308fbc745c9af - <_3:checksumValue>50a3349a079123b6bddf3db507df0dd9e877e246 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./debugger/static/webui.js - <_3:checksum rdf:nodeID="NukVOfZA52"/> - - - - <_3:checksumValue>5ebff36a2dd7cb495eed358c59670541c6c8be19 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - <_3:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2015-09-12T02:15:22Z - - <_3:licenseListVersion>1.20 - <_3:creator>Organization: duktape.org - - - + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP102"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_proxy.c - <_3:checksum rdf:nodeID="NukVOfZA388"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./polyfills/duktape-isfastint.js - <_3:checksum rdf:nodeID="NukVOfZA432"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_replacements.c - <_3:checksum rdf:nodeID="NukVOfZA410"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_selftest.h - <_3:checksum rdf:nodeID="NukVOfZA286"/> - - - - <_3:checksumValue>92ce3decf72b10b0023116ac727a752e8749aa90 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>a8c0b54002a3a7d8c69d385e7fbcf4b70d1efc70 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>3b8236810650f4e28bd84984b3c7e55029f241b0 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/guide/uppercase.c - <_3:checksum rdf:nodeID="NukVOfZA122"/> - - - <_3:packageVerificationCodeValue>39d0d436fe36ae0901ab8ed9cbdaf379037760fb - <_3:packageVerificationCodeExcludedFile>./license.spdx - - - - <_3:checksumValue>089c395fca3cedceec09fd38d32d0c77dc8658f4 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_util_misc.c - <_3:checksum rdf:nodeID="NukVOfZA218"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/eventloop/README.rst - <_3:checksum rdf:nodeID="NukVOfZA94"/> - - - - <_3:checksumValue>6b98824e13a3d9536542b8da51d012a3d66ceec1 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>6d5f56a1b76f9dcc9bb68d62ad0df958bd4d38ec - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>ddbc206357dd4b97f3630b87bfdac148a5e8b190 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>03cad085177f1e776be90afceef1f2160e6c8bf4 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>c2d899e7f2343579f29ad3079fde44eec5d6a544 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hbuffer_alloc.c - <_3:checksum rdf:nodeID="NukVOfZA234"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./debugger/duk_debug.js - <_3:checksum rdf:nodeID="NukVOfZA36"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/codepage-conv/duk_codepage_conv.h - <_3:checksum rdf:nodeID="NukVOfZA78"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/guide/fib.js - <_3:checksum rdf:nodeID="NukVOfZA124"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_js_executor.c - <_3:checksum rdf:nodeID="NukVOfZA374"/> - - - - <_3:checksumValue>78e85afbf3394e8f79b30bdcbd479faf8781e25d - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>afd3e5c9becf5feecaf57e4c5586b83da1ca61c3 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hobject_pc2line.c - <_3:checksum rdf:nodeID="NukVOfZA250"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_function.c - <_3:checksum rdf:nodeID="NukVOfZA202"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heap_refcount.c - <_3:checksum rdf:nodeID="NukVOfZA310"/> - - - - <_3:checksumValue>7b1e7e495bd7199d2e50c20e672c7fc01fcd3a42 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_duktape.c - <_3:checksum rdf:nodeID="NukVOfZA366"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_js_compiler.c - <_3:checksum rdf:nodeID="NukVOfZA214"/> - - - - <_3:checksumValue>3d8403c0150e1633ddb87362bc3d85518e26cd6a - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>6da918cc81769eeeb7c2fe20b549aebf744f175a - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_util.h - <_3:checksum rdf:nodeID="NukVOfZA206"/> - - - - <_3:checksumValue>64566ae0bdc1c3e1017604b6b45d515c30d976eb - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>881f1b114c9fbba139044ddcbbc5398243185d10 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:describesPackage rdf:nodeID="NukVOfZA4"/> - <_3:specVersion>SPDX-1.2 - <_3:dataLicense rdf:resource="http://spdx.org/licenses/CC0-1.0"/> - <_3:referencesFile rdf:nodeID="NukVOfZA85"/> - <_3:referencesFile rdf:nodeID="NukVOfZA159"/> - <_3:referencesFile rdf:nodeID="NukVOfZA189"/> - <_3:referencesFile rdf:nodeID="NukVOfZA269"/> - <_3:referencesFile rdf:nodeID="NukVOfZA447"/> - <_3:referencesFile rdf:nodeID="NukVOfZA403"/> - <_3:referencesFile rdf:nodeID="NukVOfZA191"/> - <_3:referencesFile rdf:nodeID="NukVOfZA255"/> - <_3:referencesFile rdf:nodeID="NukVOfZA61"/> - <_3:referencesFile rdf:nodeID="NukVOfZA267"/> - <_3:referencesFile rdf:nodeID="NukVOfZA23"/> - <_3:referencesFile rdf:nodeID="NukVOfZA179"/> - <_3:referencesFile rdf:nodeID="NukVOfZA271"/> - <_3:referencesFile rdf:nodeID="NukVOfZA197"/> - <_3:referencesFile rdf:nodeID="NukVOfZA367"/> - <_3:referencesFile rdf:nodeID="NukVOfZA365"/> - <_3:referencesFile rdf:nodeID="NukVOfZA425"/> - <_3:referencesFile rdf:nodeID="NukVOfZA351"/> - <_3:referencesFile rdf:nodeID="NukVOfZA317"/> - <_3:referencesFile rdf:nodeID="NukVOfZA211"/> - <_3:referencesFile rdf:nodeID="NukVOfZA207"/> - <_3:referencesFile rdf:nodeID="NukVOfZA431"/> - <_3:referencesFile rdf:nodeID="NukVOfZA331"/> - <_3:referencesFile rdf:nodeID="NukVOfZA33"/> - <_3:referencesFile rdf:nodeID="NukVOfZA285"/> - <_3:referencesFile rdf:nodeID="NukVOfZA371"/> - <_3:referencesFile rdf:nodeID="NukVOfZA423"/> - <_3:referencesFile rdf:nodeID="NukVOfZA199"/> - <_3:referencesFile rdf:nodeID="NukVOfZA163"/> - <_3:referencesFile rdf:nodeID="NukVOfZA81"/> - <_3:referencesFile rdf:nodeID="NukVOfZA291"/> - <_3:referencesFile rdf:nodeID="NukVOfZA25"/> - <_3:referencesFile rdf:nodeID="NukVOfZA97"/> - <_3:referencesFile rdf:nodeID="NukVOfZA341"/> - <_3:referencesFile rdf:nodeID="NukVOfZA339"/> - <_3:referencesFile rdf:nodeID="NukVOfZA217"/> - <_3:referencesFile rdf:nodeID="NukVOfZA93"/> - <_3:referencesFile rdf:nodeID="NukVOfZA175"/> - <_3:referencesFile rdf:nodeID="NukVOfZA193"/> - <_3:referencesFile rdf:nodeID="NukVOfZA117"/> - <_3:referencesFile rdf:nodeID="NukVOfZA377"/> - <_3:referencesFile rdf:nodeID="NukVOfZA69"/> - <_3:referencesFile rdf:nodeID="NukVOfZA75"/> - <_3:referencesFile rdf:nodeID="NukVOfZA21"/> - <_3:referencesFile rdf:nodeID="NukVOfZA111"/> - <_3:referencesFile rdf:nodeID="NukVOfZA63"/> - <_3:referencesFile rdf:nodeID="NukVOfZA287"/> - <_3:referencesFile rdf:nodeID="NukVOfZA239"/> - <_3:referencesFile rdf:nodeID="NukVOfZA147"/> - <_3:referencesFile rdf:nodeID="NukVOfZA233"/> - <_3:referencesFile rdf:nodeID="NukVOfZA89"/> - <_3:referencesFile rdf:nodeID="NukVOfZA181"/> - <_3:referencesFile rdf:nodeID="NukVOfZA77"/> - <_3:referencesFile rdf:nodeID="NukVOfZA79"/> - <_3:referencesFile rdf:nodeID="NukVOfZA123"/> - <_3:referencesFile rdf:nodeID="NukVOfZA373"/> - <_3:referencesFile rdf:nodeID="NukVOfZA319"/> - <_3:referencesFile rdf:nodeID="NukVOfZA131"/> - <_3:referencesFile rdf:nodeID="NukVOfZA137"/> - <_3:referencesFile rdf:nodeID="NukVOfZA249"/> - <_3:referencesFile rdf:nodeID="NukVOfZA201"/> - <_3:referencesFile rdf:nodeID="NukVOfZA437"/> - <_3:referencesFile rdf:nodeID="NukVOfZA417"/> - <_3:referencesFile rdf:nodeID="NukVOfZA309"/> - <_3:referencesFile rdf:nodeID="NukVOfZA393"/> - <_3:referencesFile rdf:nodeID="NukVOfZA157"/> - <_3:referencesFile rdf:nodeID="NukVOfZA241"/> - <_3:referencesFile rdf:nodeID="NukVOfZA213"/> - <_3:referencesFile rdf:nodeID="NukVOfZA419"/> - <_3:referencesFile rdf:nodeID="NukVOfZA101"/> - <_3:referencesFile rdf:nodeID="NukVOfZA235"/> - <_3:referencesFile rdf:nodeID="NukVOfZA205"/> - <_3:referencesFile rdf:nodeID="NukVOfZA143"/> - <_3:referencesFile rdf:nodeID="NukVOfZA363"/> - <_3:referencesFile rdf:nodeID="NukVOfZA221"/> - <_3:referencesFile rdf:nodeID="NukVOfZA289"/> - <_3:referencesFile rdf:nodeID="NukVOfZA135"/> - <_3:referencesFile rdf:nodeID="NukVOfZA109"/> - <_3:referencesFile rdf:nodeID="NukVOfZA35"/> - <_3:referencesFile rdf:nodeID="NukVOfZA439"/> - <_3:referencesFile rdf:nodeID="NukVOfZA399"/> - <_3:referencesFile rdf:nodeID="NukVOfZA411"/> - <_3:referencesFile rdf:nodeID="NukVOfZA307"/> - <_3:referencesFile rdf:nodeID="NukVOfZA169"/> - <_3:referencesFile rdf:nodeID="NukVOfZA203"/> - <_3:referencesFile rdf:nodeID="NukVOfZA39"/> - <_3:referencesFile rdf:nodeID="NukVOfZA187"/> - <_3:referencesFile rdf:nodeID="NukVOfZA103"/> - <_3:referencesFile rdf:nodeID="NukVOfZA409"/> - <_3:referencesFile rdf:nodeID="NukVOfZA343"/> - <_3:referencesFile rdf:nodeID="NukVOfZA231"/> - <_3:referencesFile rdf:nodeID="NukVOfZA389"/> - <_3:referencesFile rdf:nodeID="NukVOfZA379"/> - <_3:referencesFile rdf:nodeID="NukVOfZA253"/> - <_3:referencesFile rdf:nodeID="NukVOfZA321"/> - <_3:referencesFile rdf:nodeID="NukVOfZA243"/> - <_3:referencesFile rdf:nodeID="NukVOfZA167"/> - <_3:referencesFile rdf:nodeID="NukVOfZA311"/> - <_3:referencesFile rdf:nodeID="NukVOfZA275"/> - <_3:referencesFile rdf:nodeID="NukVOfZA127"/> - <_3:referencesFile rdf:nodeID="NukVOfZA29"/> - <_3:referencesFile rdf:nodeID="NukVOfZA429"/> - <_3:referencesFile rdf:nodeID="NukVOfZA257"/> - <_3:referencesFile rdf:nodeID="NukVOfZA325"/> - <_3:referencesFile rdf:nodeID="NukVOfZA435"/> - <_3:referencesFile rdf:nodeID="NukVOfZA337"/> - <_3:referencesFile rdf:nodeID="NukVOfZA259"/> - <_3:referencesFile rdf:nodeID="NukVOfZA381"/> - <_3:referencesFile rdf:nodeID="NukVOfZA407"/> - <_3:referencesFile rdf:nodeID="NukVOfZA177"/> - <_3:referencesFile rdf:nodeID="NukVOfZA449"/> - <_3:referencesFile rdf:nodeID="NukVOfZA53"/> - <_3:referencesFile rdf:nodeID="NukVOfZA395"/> - <_3:referencesFile rdf:nodeID="NukVOfZA209"/> - <_3:referencesFile rdf:nodeID="NukVOfZA27"/> - <_3:referencesFile rdf:nodeID="NukVOfZA397"/> - <_3:referencesFile rdf:nodeID="NukVOfZA237"/> - <_3:referencesFile rdf:nodeID="NukVOfZA335"/> - <_3:referencesFile rdf:nodeID="NukVOfZA139"/> - <_3:referencesFile rdf:nodeID="NukVOfZA41"/> - <_3:referencesFile rdf:nodeID="NukVOfZA171"/> - <_3:referencesFile rdf:nodeID="NukVOfZA7"/> - <_3:referencesFile rdf:nodeID="NukVOfZA387"/> - <_3:referencesFile rdf:nodeID="NukVOfZA83"/> - <_3:referencesFile rdf:nodeID="NukVOfZA421"/> - <_3:referencesFile rdf:nodeID="NukVOfZA327"/> - <_3:referencesFile rdf:nodeID="NukVOfZA347"/> - <_3:referencesFile rdf:nodeID="NukVOfZA277"/> - <_3:referencesFile rdf:nodeID="NukVOfZA279"/> - <_3:referencesFile rdf:nodeID="NukVOfZA59"/> - <_3:referencesFile rdf:nodeID="NukVOfZA185"/> - <_3:referencesFile rdf:nodeID="NukVOfZA329"/> - <_3:referencesFile rdf:nodeID="NukVOfZA427"/> - <_3:referencesFile rdf:nodeID="NukVOfZA273"/> - <_3:referencesFile rdf:nodeID="NukVOfZA361"/> - <_3:referencesFile rdf:nodeID="NukVOfZA345"/> - <_3:referencesFile rdf:nodeID="NukVOfZA223"/> - <_3:referencesFile rdf:nodeID="NukVOfZA375"/> - <_3:referencesFile rdf:nodeID="NukVOfZA445"/> - <_3:referencesFile rdf:nodeID="NukVOfZA15"/> - <_3:referencesFile rdf:nodeID="NukVOfZA359"/> - <_3:referencesFile rdf:nodeID="NukVOfZA45"/> - <_3:referencesFile rdf:nodeID="NukVOfZA215"/> - <_3:referencesFile rdf:nodeID="NukVOfZA183"/> - <_3:referencesFile rdf:nodeID="NukVOfZA369"/> - <_3:referencesFile rdf:nodeID="NukVOfZA265"/> - <_3:referencesFile rdf:nodeID="NukVOfZA305"/> - <_3:referencesFile rdf:nodeID="NukVOfZA51"/> - <_3:referencesFile rdf:nodeID="NukVOfZA113"/> - <_3:referencesFile rdf:nodeID="NukVOfZA13"/> - <_3:referencesFile rdf:nodeID="NukVOfZA43"/> - <_3:referencesFile rdf:nodeID="NukVOfZA133"/> - <_3:referencesFile rdf:nodeID="NukVOfZA383"/> - <_3:referencesFile rdf:nodeID="NukVOfZA251"/> - <_3:referencesFile rdf:nodeID="NukVOfZA55"/> - <_3:referencesFile rdf:nodeID="NukVOfZA295"/> - <_3:referencesFile rdf:nodeID="NukVOfZA401"/> - <_3:referencesFile rdf:nodeID="NukVOfZA433"/> - <_3:referencesFile rdf:nodeID="NukVOfZA161"/> - <_3:referencesFile rdf:nodeID="NukVOfZA299"/> - <_3:referencesFile rdf:nodeID="NukVOfZA95"/> - <_3:referencesFile rdf:nodeID="NukVOfZA107"/> - <_3:referencesFile rdf:nodeID="NukVOfZA227"/> - <_3:referencesFile rdf:nodeID="NukVOfZA323"/> - <_3:referencesFile rdf:nodeID="NukVOfZA333"/> - <_3:referencesFile rdf:nodeID="NukVOfZA105"/> - <_3:referencesFile rdf:nodeID="NukVOfZA443"/> - <_3:referencesFile rdf:nodeID="NukVOfZA153"/> - <_3:referencesFile rdf:nodeID="NukVOfZA141"/> - <_3:referencesFile rdf:nodeID="NukVOfZA353"/> - <_3:referencesFile rdf:nodeID="NukVOfZA9"/> - <_3:referencesFile rdf:nodeID="NukVOfZA281"/> - <_3:referencesFile rdf:nodeID="NukVOfZA11"/> - <_3:referencesFile rdf:nodeID="NukVOfZA385"/> - <_3:referencesFile rdf:nodeID="NukVOfZA229"/> - <_3:referencesFile rdf:nodeID="NukVOfZA297"/> - <_3:referencesFile rdf:nodeID="NukVOfZA405"/> - <_3:referencesFile rdf:nodeID="NukVOfZA151"/> - <_3:referencesFile rdf:nodeID="NukVOfZA165"/> - <_3:referencesFile rdf:nodeID="NukVOfZA67"/> - <_3:referencesFile rdf:nodeID="NukVOfZA115"/> - <_3:referencesFile rdf:nodeID="NukVOfZA65"/> - <_3:referencesFile rdf:nodeID="NukVOfZA49"/> - <_3:referencesFile rdf:nodeID="NukVOfZA263"/> - <_3:referencesFile rdf:nodeID="NukVOfZA125"/> - <_3:referencesFile rdf:nodeID="NukVOfZA91"/> - <_3:referencesFile rdf:nodeID="NukVOfZA19"/> - <_3:referencesFile rdf:nodeID="NukVOfZA283"/> - <_3:referencesFile rdf:nodeID="NukVOfZA349"/> - <_3:referencesFile rdf:nodeID="NukVOfZA173"/> - <_3:referencesFile rdf:nodeID="NukVOfZA355"/> - <_3:referencesFile rdf:nodeID="NukVOfZA303"/> - <_3:referencesFile rdf:nodeID="NukVOfZA441"/> - <_3:referencesFile rdf:nodeID="NukVOfZA357"/> - <_3:referencesFile rdf:nodeID="NukVOfZA195"/> - <_3:referencesFile rdf:nodeID="NukVOfZA225"/> - <_3:referencesFile rdf:nodeID="NukVOfZA57"/> - <_3:referencesFile rdf:nodeID="NukVOfZA121"/> - <_3:referencesFile rdf:nodeID="NukVOfZA453"/> - <_3:referencesFile rdf:nodeID="NukVOfZA415"/> - <_3:referencesFile rdf:nodeID="NukVOfZA261"/> - <_3:referencesFile rdf:nodeID="NukVOfZA301"/> - <_3:referencesFile rdf:nodeID="NukVOfZA391"/> - <_3:referencesFile rdf:nodeID="NukVOfZA17"/> - <_3:referencesFile rdf:nodeID="NukVOfZA245"/> - <_3:referencesFile rdf:nodeID="NukVOfZA71"/> - <_3:referencesFile rdf:nodeID="NukVOfZA129"/> - <_3:referencesFile rdf:nodeID="NukVOfZA293"/> - <_3:referencesFile rdf:nodeID="NukVOfZA31"/> - <_3:referencesFile rdf:nodeID="NukVOfZA119"/> - <_3:referencesFile rdf:nodeID="NukVOfZA219"/> - <_3:referencesFile rdf:nodeID="NukVOfZA451"/> - <_3:referencesFile rdf:nodeID="NukVOfZA145"/> - <_3:referencesFile rdf:nodeID="NukVOfZA73"/> - <_3:referencesFile rdf:nodeID="NukVOfZA37"/> - <_3:referencesFile rdf:nodeID="NukVOfZA87"/> - <_3:referencesFile rdf:nodeID="NukVOfZA247"/> - <_3:referencesFile rdf:nodeID="NukVOfZA99"/> - <_3:referencesFile rdf:nodeID="NukVOfZA47"/> - <_3:referencesFile rdf:nodeID="NukVOfZA413"/> - <_3:referencesFile rdf:nodeID="NukVOfZA155"/> - <_3:referencesFile rdf:nodeID="NukVOfZA313"/> - <_3:referencesFile rdf:nodeID="NukVOfZA315"/> - <_3:referencesFile rdf:nodeID="NukVOfZA149"/> - SPDX license for Duktape 1.3.0 - <_3:creationInfo rdf:nodeID="NukVOfZA3"/> - - - - <_3:checksumValue>c14747594add785dd952855071e51077f5152bad - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>cd025a84635e6a1353f756cf9c74c27bfd36862d - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_number.c - <_3:checksum rdf:nodeID="NukVOfZA412"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_numconv.h - <_3:checksum rdf:nodeID="NukVOfZA188"/> - - - - <_3:checksumValue>f88d68880f451267e7e2eca4b6c4191e8c3fe011 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>93573df8348a41adb790f59e39bf99d9a7bf3a3d - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>75c61dd080cd643b7449f673105b7b7e4bdda0f5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_json.h - <_3:checksum rdf:nodeID="NukVOfZA322"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_js_call.c - <_3:checksum rdf:nodeID="NukVOfZA244"/> - - - - <_3:checksumValue>de9650befceae510999c0e852a79f994d74fc531 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heap_markandsweep.c - <_3:checksum rdf:nodeID="NukVOfZA312"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_util_bitdecoder.c - <_3:checksum rdf:nodeID="NukVOfZA258"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hbuffer.h - <_3:checksum rdf:nodeID="NukVOfZA326"/> - - - - <_3:checksumValue>ce19fb1254e02c8ff3ed8e0737522d6af7b977c5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>82314b509ee3b15b393fefe747c8e0169ab39aaa - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_js_ops.c - <_3:checksum rdf:nodeID="NukVOfZA396"/> - - - - <_3:checksumValue>a3d2ce3d28d6bb5afd29e35ade770a8ae5f45c3f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>a8f8cf615ef79337a83eb791477dc9ed2c22822c - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>7e2674dd72227576375a80f6ddbb11320f5b987a - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>37a995b627b3a85cecc2a5851537589d4da3bf63 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>44c9219558aba26dc69982a9f432028290707c36 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_initjs_min.js - <_3:checksum rdf:nodeID="NukVOfZA390"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_selftest.c - <_3:checksum rdf:nodeID="NukVOfZA330"/> - - - - <_3:checksumValue>59d3c2d44ed8707fa6c907a7387ffce611d89e44 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_regexp_compiler.c - <_3:checksum rdf:nodeID="NukVOfZA346"/> - - - - <_3:checksumValue>79f806448cbd4724bf60e0723414b391686be098 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_string.c - <_3:checksum rdf:nodeID="NukVOfZA392"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heap_misc.c - <_3:checksum rdf:nodeID="NukVOfZA266"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_lexer.h - <_3:checksum rdf:nodeID="NukVOfZA306"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/eval/README.rst - <_3:checksum rdf:nodeID="NukVOfZA114"/> - - - - <_3:checksumValue>11ecfff4142b35382d0aaf80ee6c04ae3dfd0b4c - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./debugger/package.json - <_3:checksum rdf:nodeID="NukVOfZA44"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_internal.h - <_3:checksum rdf:nodeID="NukVOfZA296"/> - - - - <_3:checksumValue>47e1001460004f53dfc350355e02bf56f18b0398 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/server-socket-test.js - <_3:checksum rdf:nodeID="NukVOfZA108"/> - - - - <_3:checksumValue>43a0dfbf1cb06dbfe3a37959ad1b93bc036f78cb - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/client-socket-test.js - <_3:checksum rdf:nodeID="NukVOfZA106"/> - - - - <_3:checksumValue>b5f54e8a18d5dc9a791cb36976a7d2345d26b549 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./duk_build_meta.json - <_3:checksum rdf:nodeID="NukVOfZA10"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./README.rst - <_3:checksum rdf:nodeID="NukVOfZA12"/> - - - - <_3:checksumValue>a9c998dbedde09cc435eec0ac1a3a428090b37a9 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hbufferobject_misc.c - <_3:checksum rdf:nodeID="NukVOfZA298"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_debug.c - <_3:checksum rdf:nodeID="NukVOfZA196"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/alloc-hybrid/README.rst - <_3:checksum rdf:nodeID="NukVOfZA68"/> - - - - <_3:checksumValue>8d307ae071694f3d2242578c7d88bcae5c2ef7de - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heap_hashstring.c - <_3:checksum rdf:nodeID="NukVOfZA350"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/alloc-logging/README.rst - <_3:checksum rdf:nodeID="NukVOfZA174"/> - - - - <_3:checksumValue>e5a5f0db067ec56c6d2f7356f412222a8884dc92 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./config/genconfig_metadata.tar.gz - <_3:checksum rdf:nodeID="NukVOfZA442"/> - - - - <_3:checksumValue>d68dbb37b698f98f51a9136d4026b2ac0a2911c4 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>6a1500fea27ea278c4f0c64d908e16cc60df684b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:name>Duktape - <_3:originator>Organization: duktape.org - <_3:versionInfo>1.3.0 - <_3:packageVerificationCode rdf:nodeID="NukVOfZA5"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:summary>Duktape Ecmascript interpreter - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:downloadLocation rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">http://duktape.org/duktape-1.3.0.tar.xz - <_3:homePage rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">http://duktape.org/ - <_3:licenseDeclared rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseComments>Duktape is copyrighted by its authors and licensed under the MIT license. MurmurHash2 is used internally, it is also under the MIT license. Duktape module loader is based on the CommonJS module loading specification (without sharing any code), CommonJS is under the MIT license. - <_3:supplier>Organization: duktape.org - <_3:sourceInfo>Official duktape.org release built from GitHub repo https://github.com/svaarala/duktape. - <_3:licenseInfoFromFiles rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:packageFileName>duktape-1.3.0.tar.xz - <_3:hasFile rdf:nodeID="NukVOfZA85"/> - <_3:hasFile rdf:nodeID="NukVOfZA159"/> - <_3:hasFile rdf:nodeID="NukVOfZA189"/> - <_3:hasFile rdf:nodeID="NukVOfZA269"/> - <_3:hasFile rdf:nodeID="NukVOfZA447"/> - <_3:hasFile rdf:nodeID="NukVOfZA403"/> - <_3:hasFile rdf:nodeID="NukVOfZA191"/> - <_3:hasFile rdf:nodeID="NukVOfZA255"/> - <_3:hasFile rdf:nodeID="NukVOfZA61"/> - <_3:hasFile rdf:nodeID="NukVOfZA267"/> - <_3:hasFile rdf:nodeID="NukVOfZA23"/> - <_3:hasFile rdf:nodeID="NukVOfZA179"/> - <_3:hasFile rdf:nodeID="NukVOfZA271"/> - <_3:hasFile rdf:nodeID="NukVOfZA197"/> - <_3:hasFile rdf:nodeID="NukVOfZA367"/> - <_3:hasFile rdf:nodeID="NukVOfZA365"/> - <_3:hasFile rdf:nodeID="NukVOfZA425"/> - <_3:hasFile rdf:nodeID="NukVOfZA351"/> - <_3:hasFile rdf:nodeID="NukVOfZA317"/> - <_3:hasFile rdf:nodeID="NukVOfZA211"/> - <_3:hasFile rdf:nodeID="NukVOfZA207"/> - <_3:hasFile rdf:nodeID="NukVOfZA431"/> - <_3:hasFile rdf:nodeID="NukVOfZA331"/> - <_3:hasFile rdf:nodeID="NukVOfZA33"/> - <_3:hasFile rdf:nodeID="NukVOfZA285"/> - <_3:hasFile rdf:nodeID="NukVOfZA371"/> - <_3:hasFile rdf:nodeID="NukVOfZA423"/> - <_3:hasFile rdf:nodeID="NukVOfZA199"/> - <_3:hasFile rdf:nodeID="NukVOfZA163"/> - <_3:hasFile rdf:nodeID="NukVOfZA81"/> - <_3:hasFile rdf:nodeID="NukVOfZA291"/> - <_3:hasFile rdf:nodeID="NukVOfZA25"/> - <_3:hasFile rdf:nodeID="NukVOfZA97"/> - <_3:hasFile rdf:nodeID="NukVOfZA341"/> - <_3:hasFile rdf:nodeID="NukVOfZA339"/> - <_3:hasFile rdf:nodeID="NukVOfZA217"/> - <_3:hasFile rdf:nodeID="NukVOfZA93"/> - <_3:hasFile rdf:nodeID="NukVOfZA175"/> - <_3:hasFile rdf:nodeID="NukVOfZA193"/> - <_3:hasFile rdf:nodeID="NukVOfZA117"/> - <_3:hasFile rdf:nodeID="NukVOfZA377"/> - <_3:hasFile rdf:nodeID="NukVOfZA69"/> - <_3:hasFile rdf:nodeID="NukVOfZA75"/> - <_3:hasFile rdf:nodeID="NukVOfZA21"/> - <_3:hasFile rdf:nodeID="NukVOfZA111"/> - <_3:hasFile rdf:nodeID="NukVOfZA63"/> - <_3:hasFile rdf:nodeID="NukVOfZA287"/> - <_3:hasFile rdf:nodeID="NukVOfZA239"/> - <_3:hasFile rdf:nodeID="NukVOfZA147"/> - <_3:hasFile rdf:nodeID="NukVOfZA233"/> - <_3:hasFile rdf:nodeID="NukVOfZA89"/> - <_3:hasFile rdf:nodeID="NukVOfZA181"/> - <_3:hasFile rdf:nodeID="NukVOfZA77"/> - <_3:hasFile rdf:nodeID="NukVOfZA79"/> - <_3:hasFile rdf:nodeID="NukVOfZA123"/> - <_3:hasFile rdf:nodeID="NukVOfZA373"/> - <_3:hasFile rdf:nodeID="NukVOfZA319"/> - <_3:hasFile rdf:nodeID="NukVOfZA131"/> - <_3:hasFile rdf:nodeID="NukVOfZA137"/> - <_3:hasFile rdf:nodeID="NukVOfZA249"/> - <_3:hasFile rdf:nodeID="NukVOfZA201"/> - <_3:hasFile rdf:nodeID="NukVOfZA437"/> - <_3:hasFile rdf:nodeID="NukVOfZA417"/> - <_3:hasFile rdf:nodeID="NukVOfZA309"/> - <_3:hasFile rdf:nodeID="NukVOfZA393"/> - <_3:hasFile rdf:nodeID="NukVOfZA157"/> - <_3:hasFile rdf:nodeID="NukVOfZA241"/> - <_3:hasFile rdf:nodeID="NukVOfZA213"/> - <_3:hasFile rdf:nodeID="NukVOfZA419"/> - <_3:hasFile rdf:nodeID="NukVOfZA101"/> - <_3:hasFile rdf:nodeID="NukVOfZA235"/> - <_3:hasFile rdf:nodeID="NukVOfZA205"/> - <_3:hasFile rdf:nodeID="NukVOfZA143"/> - <_3:hasFile rdf:nodeID="NukVOfZA363"/> - <_3:hasFile rdf:nodeID="NukVOfZA221"/> - <_3:hasFile rdf:nodeID="NukVOfZA289"/> - <_3:hasFile rdf:nodeID="NukVOfZA135"/> - <_3:hasFile rdf:nodeID="NukVOfZA109"/> - <_3:hasFile rdf:nodeID="NukVOfZA35"/> - <_3:hasFile rdf:nodeID="NukVOfZA439"/> - <_3:hasFile rdf:nodeID="NukVOfZA399"/> - <_3:hasFile rdf:nodeID="NukVOfZA411"/> - <_3:hasFile rdf:nodeID="NukVOfZA307"/> - <_3:hasFile rdf:nodeID="NukVOfZA169"/> - <_3:hasFile rdf:nodeID="NukVOfZA203"/> - <_3:hasFile rdf:nodeID="NukVOfZA39"/> - <_3:hasFile rdf:nodeID="NukVOfZA187"/> - <_3:hasFile rdf:nodeID="NukVOfZA103"/> - <_3:hasFile rdf:nodeID="NukVOfZA409"/> - <_3:hasFile rdf:nodeID="NukVOfZA343"/> - <_3:hasFile rdf:nodeID="NukVOfZA231"/> - <_3:hasFile rdf:nodeID="NukVOfZA389"/> - <_3:hasFile rdf:nodeID="NukVOfZA379"/> - <_3:hasFile rdf:nodeID="NukVOfZA253"/> - <_3:hasFile rdf:nodeID="NukVOfZA321"/> - <_3:hasFile rdf:nodeID="NukVOfZA243"/> - <_3:hasFile rdf:nodeID="NukVOfZA167"/> - <_3:hasFile rdf:nodeID="NukVOfZA311"/> - <_3:hasFile rdf:nodeID="NukVOfZA275"/> - <_3:hasFile rdf:nodeID="NukVOfZA127"/> - <_3:hasFile rdf:nodeID="NukVOfZA29"/> - <_3:hasFile rdf:nodeID="NukVOfZA429"/> - <_3:hasFile rdf:nodeID="NukVOfZA257"/> - <_3:hasFile rdf:nodeID="NukVOfZA325"/> - <_3:hasFile rdf:nodeID="NukVOfZA435"/> - <_3:hasFile rdf:nodeID="NukVOfZA337"/> - <_3:hasFile rdf:nodeID="NukVOfZA259"/> - <_3:hasFile rdf:nodeID="NukVOfZA381"/> - <_3:hasFile rdf:nodeID="NukVOfZA407"/> - <_3:hasFile rdf:nodeID="NukVOfZA177"/> - <_3:hasFile rdf:nodeID="NukVOfZA449"/> - <_3:hasFile rdf:nodeID="NukVOfZA53"/> - <_3:hasFile rdf:nodeID="NukVOfZA395"/> - <_3:hasFile rdf:nodeID="NukVOfZA209"/> - <_3:hasFile rdf:nodeID="NukVOfZA27"/> - <_3:hasFile rdf:nodeID="NukVOfZA397"/> - <_3:hasFile rdf:nodeID="NukVOfZA237"/> - <_3:hasFile rdf:nodeID="NukVOfZA335"/> - <_3:hasFile rdf:nodeID="NukVOfZA139"/> - <_3:hasFile rdf:nodeID="NukVOfZA41"/> - <_3:hasFile rdf:nodeID="NukVOfZA171"/> - <_3:hasFile rdf:nodeID="NukVOfZA7"/> - <_3:hasFile rdf:nodeID="NukVOfZA387"/> - <_3:hasFile rdf:nodeID="NukVOfZA83"/> - <_3:hasFile rdf:nodeID="NukVOfZA421"/> - <_3:hasFile rdf:nodeID="NukVOfZA327"/> - <_3:hasFile rdf:nodeID="NukVOfZA347"/> - <_3:hasFile rdf:nodeID="NukVOfZA277"/> - <_3:hasFile rdf:nodeID="NukVOfZA279"/> - <_3:hasFile rdf:nodeID="NukVOfZA59"/> - <_3:hasFile rdf:nodeID="NukVOfZA185"/> - <_3:hasFile rdf:nodeID="NukVOfZA329"/> - <_3:hasFile rdf:nodeID="NukVOfZA427"/> - <_3:hasFile rdf:nodeID="NukVOfZA273"/> - <_3:hasFile rdf:nodeID="NukVOfZA361"/> - <_3:hasFile rdf:nodeID="NukVOfZA345"/> - <_3:hasFile rdf:nodeID="NukVOfZA223"/> - <_3:hasFile rdf:nodeID="NukVOfZA375"/> - <_3:hasFile rdf:nodeID="NukVOfZA445"/> - <_3:hasFile rdf:nodeID="NukVOfZA15"/> - <_3:hasFile rdf:nodeID="NukVOfZA359"/> - <_3:hasFile rdf:nodeID="NukVOfZA45"/> - <_3:hasFile rdf:nodeID="NukVOfZA215"/> - <_3:hasFile rdf:nodeID="NukVOfZA183"/> - <_3:hasFile rdf:nodeID="NukVOfZA369"/> - <_3:hasFile rdf:nodeID="NukVOfZA265"/> - <_3:hasFile rdf:nodeID="NukVOfZA305"/> - <_3:hasFile rdf:nodeID="NukVOfZA51"/> - <_3:hasFile rdf:nodeID="NukVOfZA113"/> - <_3:hasFile rdf:nodeID="NukVOfZA13"/> - <_3:hasFile rdf:nodeID="NukVOfZA43"/> - <_3:hasFile rdf:nodeID="NukVOfZA133"/> - <_3:hasFile rdf:nodeID="NukVOfZA383"/> - <_3:hasFile rdf:nodeID="NukVOfZA251"/> - <_3:hasFile rdf:nodeID="NukVOfZA55"/> - <_3:hasFile rdf:nodeID="NukVOfZA295"/> - <_3:hasFile rdf:nodeID="NukVOfZA401"/> - <_3:hasFile rdf:nodeID="NukVOfZA433"/> - <_3:hasFile rdf:nodeID="NukVOfZA161"/> - <_3:hasFile rdf:nodeID="NukVOfZA299"/> - <_3:hasFile rdf:nodeID="NukVOfZA95"/> - <_3:hasFile rdf:nodeID="NukVOfZA107"/> - <_3:hasFile rdf:nodeID="NukVOfZA227"/> - <_3:hasFile rdf:nodeID="NukVOfZA323"/> - <_3:hasFile rdf:nodeID="NukVOfZA333"/> - <_3:hasFile rdf:nodeID="NukVOfZA105"/> - <_3:hasFile rdf:nodeID="NukVOfZA443"/> - <_3:hasFile rdf:nodeID="NukVOfZA153"/> - <_3:hasFile rdf:nodeID="NukVOfZA141"/> - <_3:hasFile rdf:nodeID="NukVOfZA353"/> - <_3:hasFile rdf:nodeID="NukVOfZA9"/> - <_3:hasFile rdf:nodeID="NukVOfZA281"/> - <_3:hasFile rdf:nodeID="NukVOfZA11"/> - <_3:hasFile rdf:nodeID="NukVOfZA385"/> - <_3:hasFile rdf:nodeID="NukVOfZA229"/> - <_3:hasFile rdf:nodeID="NukVOfZA297"/> - <_3:hasFile rdf:nodeID="NukVOfZA405"/> - <_3:hasFile rdf:nodeID="NukVOfZA151"/> - <_3:hasFile rdf:nodeID="NukVOfZA165"/> - <_3:hasFile rdf:nodeID="NukVOfZA67"/> - <_3:hasFile rdf:nodeID="NukVOfZA115"/> - <_3:hasFile rdf:nodeID="NukVOfZA65"/> - <_3:hasFile rdf:nodeID="NukVOfZA49"/> - <_3:hasFile rdf:nodeID="NukVOfZA263"/> - <_3:hasFile rdf:nodeID="NukVOfZA125"/> - <_3:hasFile rdf:nodeID="NukVOfZA91"/> - <_3:hasFile rdf:nodeID="NukVOfZA19"/> - <_3:hasFile rdf:nodeID="NukVOfZA283"/> - <_3:hasFile rdf:nodeID="NukVOfZA349"/> - <_3:hasFile rdf:nodeID="NukVOfZA173"/> - <_3:hasFile rdf:nodeID="NukVOfZA355"/> - <_3:hasFile rdf:nodeID="NukVOfZA303"/> - <_3:hasFile rdf:nodeID="NukVOfZA441"/> - <_3:hasFile rdf:nodeID="NukVOfZA357"/> - <_3:hasFile rdf:nodeID="NukVOfZA195"/> - <_3:hasFile rdf:nodeID="NukVOfZA225"/> - <_3:hasFile rdf:nodeID="NukVOfZA57"/> - <_3:hasFile rdf:nodeID="NukVOfZA121"/> - <_3:hasFile rdf:nodeID="NukVOfZA453"/> - <_3:hasFile rdf:nodeID="NukVOfZA415"/> - <_3:hasFile rdf:nodeID="NukVOfZA261"/> - <_3:hasFile rdf:nodeID="NukVOfZA301"/> - <_3:hasFile rdf:nodeID="NukVOfZA391"/> - <_3:hasFile rdf:nodeID="NukVOfZA17"/> - <_3:hasFile rdf:nodeID="NukVOfZA245"/> - <_3:hasFile rdf:nodeID="NukVOfZA71"/> - <_3:hasFile rdf:nodeID="NukVOfZA129"/> - <_3:hasFile rdf:nodeID="NukVOfZA293"/> - <_3:hasFile rdf:nodeID="NukVOfZA31"/> - <_3:hasFile rdf:nodeID="NukVOfZA119"/> - <_3:hasFile rdf:nodeID="NukVOfZA219"/> - <_3:hasFile rdf:nodeID="NukVOfZA451"/> - <_3:hasFile rdf:nodeID="NukVOfZA145"/> - <_3:hasFile rdf:nodeID="NukVOfZA73"/> - <_3:hasFile rdf:nodeID="NukVOfZA37"/> - <_3:hasFile rdf:nodeID="NukVOfZA87"/> - <_3:hasFile rdf:nodeID="NukVOfZA247"/> - <_3:hasFile rdf:nodeID="NukVOfZA99"/> - <_3:hasFile rdf:nodeID="NukVOfZA47"/> - <_3:hasFile rdf:nodeID="NukVOfZA413"/> - <_3:hasFile rdf:nodeID="NukVOfZA155"/> - <_3:hasFile rdf:nodeID="NukVOfZA313"/> - <_3:hasFile rdf:nodeID="NukVOfZA315"/> - <_3:hasFile rdf:nodeID="NukVOfZA149"/> - <_3:description>Duktape is an embeddable Javascript engine, with a focus on portability and compact footprint - - - - <_3:checksumValue>2cdc31948853f9f0bf0d5f726b6034c508ee9d67 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_forwdecl.h - <_3:checksum rdf:nodeID="NukVOfZA240"/> - - - - <_3:checksumValue>e2a167fd8048cbd7c85fd62da70749b2a0109b2a - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src/duktape.h - <_3:checksum rdf:nodeID="NukVOfZA454"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eval/eval.c - <_3:checksum rdf:nodeID="NukVOfZA116"/> - - - - <_3:checksumValue>a8e7b9b9bed773ecc7e08f4b73716dad741fd50b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>4ee4843558692861cb91a6c6906539795b639091 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> <_3:fileName>./examples/eventloop/main.c - <_3:checksum rdf:nodeID="NukVOfZA84"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./Makefile.eventloop - <_3:checksum rdf:nodeID="NukVOfZA32"/> - - - - <_3:checksumValue>d84a903a426cf3a158072565161c35240a1c68e5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>206ffd13c06208e85baba2b257fe3ddebb56a6c2 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>6b150b9183cc8453536713de0d1e79adc21a3fee - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/curses-timers.js - <_3:checksum rdf:nodeID="NukVOfZA100"/> - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./debugger/duk_opcodes.yaml - <_3:checksum rdf:nodeID="NukVOfZA48"/> - - - + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> <_3:checksumValue>bd2f85dccd23b76b9cf9900b8b2b86f0bf97421b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - <_3:checksumValue>e4d3286030d5ef1e74dd07a5b2efa37cd907697e - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - <_3:checksumValue>d48fe743ca18b8b3205d6443a08463d6b0334153 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>61043b4a6f3cf86375ea6e34ebf83b550a1935b2 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP416"/> + + <_3:fileName>./src-separate/duk_initjs_min.js <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./polyfills/object-prototype-definegetter.js - <_3:checksum rdf:nodeID="NukVOfZA426"/> - - - <_3:checksumValue>063133679b6d072efc1c27f3a510101744ffde0c - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>ca663612967cb12b33d666180d7bb3008314ca7a - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./Makefile.sandbox - <_3:checksum rdf:nodeID="NukVOfZA24"/> - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP322"/> + + <_3:fileName>./src-separate/duk_internal.h <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_tval.c - <_3:checksum rdf:nodeID="NukVOfZA398"/> - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hobject.h - <_3:checksum rdf:nodeID="NukVOfZA352"/> - - - - <_3:checksumValue>786369a33cccbadc3d2efba613a43fdd638971fc + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - + <_3:checksumValue>b7ee0e88e6365390db594e5e1a90c383847cfd0f - <_3:checksumValue>f5251445a782e4bfac8af043f24ecbac740f67eb - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - <_3:checksumValue>1bce4dadb408a2a6a77b366f0ecfc18398cbb722 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + + <_3:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2016-12-08T20:32:53Z + + <_3:licenseListVersion>1.20 + + <_3:creator>Organization: duktape.org - - - <_3:checksumValue>f65888efe272f584113d4df273cc6e7a5c5a43dd - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>df7b9fe732c2bc300d096c06d90bbdc71fada213 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_global.c - <_3:checksum rdf:nodeID="NukVOfZA200"/> - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./AUTHORS.rst - <_3:checksum rdf:nodeID="NukVOfZA26"/> - - + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP80"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/ecma_eventloop.js - <_3:checksum rdf:nodeID="NukVOfZA98"/> - - - - <_3:checksumValue>b54cd58e7947b2899eb8662d2cdaf022dd680ea6 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>ea1ee74bace7e1958d0049c1035b3832ef951e82 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>6d0092ec677f2d4aa5c91cf9f71d8aca5171c8e2 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/alloc-hybrid/duk_alloc_hybrid.c - <_3:checksum rdf:nodeID="NukVOfZA70"/> - - - - <_3:checksumValue>41f24f22ab9039c1f9a548fb75c9639453380065 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>ea413ed7d47cf27c6f3ffe25956b1370b653c200 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>d869c0f8797a659124b3ba31c75f494b15bea5e6 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_call.c - <_3:checksum rdf:nodeID="NukVOfZA226"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/debug-trans-socket/duk_trans_socket.h - <_3:checksum rdf:nodeID="NukVOfZA148"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_builtins.h - <_3:checksum rdf:nodeID="NukVOfZA182"/> - - - - <_3:checksumValue>2c811905f5b8781c8b70d099687773a8d20ce082 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_config.h - <_3:checksum rdf:nodeID="NukVOfZA336"/> - - - - <_3:checksumValue>9bb6ca1fa3ad4c593b000b2de5aca013b95adda0 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>b298f68a888cec4efea00f221053645a59748c18 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>4e5a54de08355669dc98b5d4ad379384b33da4e5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>2878666c896a9a9a4dddefd943c0ddf3a09310a4 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>07a167411a356aebfbe987353846a9c711998f20 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_thread.c - <_3:checksum rdf:nodeID="NukVOfZA394"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/debug-trans-dvalue/Makefile - <_3:checksum rdf:nodeID="NukVOfZA158"/> - - - - <_3:checksumValue>27813a75f3f27a0dcdf51e269582a97679585827 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>9a31edd2028d39d24aa9bfdbd2b70ce2a64b8493 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_stack.c - <_3:checksum rdf:nodeID="NukVOfZA404"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_jmpbuf.h - <_3:checksum rdf:nodeID="NukVOfZA190"/> - - - - <_3:checksumValue>5a72a639353c2f9e3bfb1c369246775ecd6f005e - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_unicode.h - <_3:checksum rdf:nodeID="NukVOfZA222"/> - - - - <_3:checksumValue>a2c79a55a60f73e1a1567b96d584399571180ef5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>09ee87b3ae8afe8b7c2295127835b05b00603b25 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/alloc-torture/duk_alloc_torture.h - <_3:checksum rdf:nodeID="NukVOfZA136"/> - - - - <_3:checksumValue>6b097ba4583a27d31c21b60cb15770804dd1ba9d - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>29be453689679c9bab977c0b333a4a224d9f02e6 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./config/README.rst - <_3:checksum rdf:nodeID="NukVOfZA440"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_debug_vsnprintf.c - <_3:checksum rdf:nodeID="NukVOfZA308"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/alloc-logging/log2gnuplot.py - <_3:checksum rdf:nodeID="NukVOfZA170"/> - - - - <_3:checksumValue>5d56f0bab3e87abdca8da4d6e8580cb9132fd697 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>5f3b6cd81be97aa687fe8b47751e68b5561d7c1b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>b6cf7cd6cdf526aa3cf60144c6a9569e6d112f36 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/alloc-logging/duk_alloc_logging.c - <_3:checksum rdf:nodeID="NukVOfZA168"/> - - - - <_3:checksumValue>7edf7600e1a6f09d1e4a0e2f9be418b59fff7c52 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>16a4c10bea273a74018fa0a7a8889b7b43a3119b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>0053a77d6c3562af6d2238f096f3a9bd4b5a834f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/coffee/hello.coffee - <_3:checksum rdf:nodeID="NukVOfZA60"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./Makefile.eval - <_3:checksum rdf:nodeID="NukVOfZA30"/> - - - - <_3:checksumValue>b2872f0cbb3cbe10184bbc3a95b1d7c365b8ed32 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>a5afcd26ab65a29d95a6e33bf0f33645ee4fd91b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./polyfills/performance-now.js - <_3:checksum rdf:nodeID="NukVOfZA436"/> - - - - <_3:checksumValue>32a98d7fe78d83f08173234229f862698fce2090 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duktape.h - <_3:checksum rdf:nodeID="NukVOfZA408"/> - - - - <_3:checksumValue>02b01faf5220448b3d678abba34a0a9be96d71ca - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>ff17cbc9cb84b86f83bb104a247e5c265a9fe5b5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./Makefile.dukdebug - <_3:checksum rdf:nodeID="NukVOfZA28"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/guide/prime.js - <_3:checksum rdf:nodeID="NukVOfZA130"/> - - - - <_3:checksumValue>14ec83aeef66a38c6a4c48a175a544f66d319413 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_pointer.c - <_3:checksum rdf:nodeID="NukVOfZA422"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_unicode_tables.c - <_3:checksum rdf:nodeID="NukVOfZA278"/> - - - - <_3:checksumValue>29b1960bc40607c2cf496465068611b2ffc4de87 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>b398df12e0b18a0e3edca6c4d55f7575cea9a76a - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>f437b6a49e9ad85f1bed504b9d7724358eb37ad8 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_var.c - <_3:checksum rdf:nodeID="NukVOfZA402"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_date_windows.c - <_3:checksum rdf:nodeID="NukVOfZA376"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./mandel.js - <_3:checksum rdf:nodeID="NukVOfZA16"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heap_alloc.c - <_3:checksum rdf:nodeID="NukVOfZA360"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_regexp_executor.c - <_3:checksum rdf:nodeID="NukVOfZA184"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_debugger.c - <_3:checksum rdf:nodeID="NukVOfZA384"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heap_stringtable.c - <_3:checksum rdf:nodeID="NukVOfZA252"/> - - - - <_3:checksumValue>11f16b15a8e52598a078b88a8d0440ff61dd5ba2 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>1eb3bb219637be52abe8a154551ec76bfc5ecf31 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hthread_alloc.c - <_3:checksum rdf:nodeID="NukVOfZA334"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./extras/README.rst - <_3:checksum rdf:nodeID="NukVOfZA444"/> - - - - <_3:checksumValue>58c701ade28ee5a475dede84a6e771893e3fc40f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_array.c - <_3:checksum rdf:nodeID="NukVOfZA354"/> - - - - <_3:checksumValue>6961515d6681b7dfb59d2d080b87cdeb2a673025 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_replacements.h - <_3:checksum rdf:nodeID="NukVOfZA282"/> - - - - <_3:checksumValue>89ce4d46fcef5a35b3b6652d79ebe556b121d2a8 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_js_bytecode.h - <_3:checksum rdf:nodeID="NukVOfZA230"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_util_hashbytes.c - <_3:checksum rdf:nodeID="NukVOfZA406"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./debugger/static/style.css - <_3:checksum rdf:nodeID="NukVOfZA50"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./Makefile.coffee - <_3:checksum rdf:nodeID="NukVOfZA20"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src/duk_config.h - <_3:checksum rdf:nodeID="NukVOfZA450"/> - - - - <_3:checksumValue>3948c3f17d6863157361cb817b6bc7bf7799122f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_compile.c - <_3:checksum rdf:nodeID="NukVOfZA358"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/coffee/mandel.coffee - <_3:checksum rdf:nodeID="NukVOfZA58"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_debug_fixedbuffer.c - <_3:checksum rdf:nodeID="NukVOfZA416"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_date.c - <_3:checksum rdf:nodeID="NukVOfZA246"/> - - - - <_3:checksumValue>4d3ab8c2d41261b0cae627db9d536d26f72b5f8e - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_util_bufwriter.c - <_3:checksum rdf:nodeID="NukVOfZA186"/> - - - - <_3:checksumValue>4588ca1842f93e72254f9b428d6d07ad22b57163 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/cmdline/README.rst - <_3:checksum rdf:nodeID="NukVOfZA146"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/ncurses.c - <_3:checksum rdf:nodeID="NukVOfZA88"/> - - - - <_3:checksumValue>d90697f65158589fb137e9a48cbf288bde2ef230 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/debug-trans-dvalue/README.rst - <_3:checksum rdf:nodeID="NukVOfZA156"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hcompiledfunction.h - <_3:checksum rdf:nodeID="NukVOfZA304"/> - - - - <_3:checksumValue>a9db75839022e7dcf7e691ada7480a9b7c2715d0 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>3d700df1f765c39fc63bfd4e31a9d7da8d15c543 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hthread_builtins.c - <_3:checksum rdf:nodeID="NukVOfZA270"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> <_3:fileName>./examples/coffee/README.rst - <_3:checksum rdf:nodeID="NukVOfZA62"/> - - - - <_3:checksumValue>5f89525f75f61dd8c89e010cb62bc071d6d13170 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>7b236da6f48b6f6aef43e6c959b43edaa8120ff4 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>ad475950dc26e62ba57f5bfa266687681b09e10f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>fa85ee3394206d18c611b837e700257ba8336250 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_debug_macros.c - <_3:checksum rdf:nodeID="NukVOfZA424"/> - - - - <_3:checksumValue>8521b45dcbc72d66c2b4e3f0db9e1dbfb75b45f5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_memory.c - <_3:checksum rdf:nodeID="NukVOfZA318"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hstring_misc.c - <_3:checksum rdf:nodeID="NukVOfZA208"/> - - - - <_3:checksumValue>2c2b647e4cf2c94e91f5193987a01a029bf01690 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./Makefile.jxpretty - <_3:checksum rdf:nodeID="NukVOfZA34"/> - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP276"/> + + <_3:fileName>./src-separate/duk_heap_stringtable.c <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_regexp.c - <_3:checksum rdf:nodeID="NukVOfZA372"/> - - - <_3:checksumValue>484fb41d516abcbe8c97af5aa80b76c67dbfb0cb + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - + <_3:checksumValue>d70b4083ccd3b5dac32ad07e58d3132dc3390b79 - <_3:checksumValue>7108fbe42728e2fe1c2448b119a6a1f52568ce53 + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/jxpretty/jxpretty.c - <_3:checksum rdf:nodeID="NukVOfZA82"/> - - + <_3:checksumValue>f051b42ff42dc8655b9e17739f7cb7cb76bdf78d - <_3:checksumValue>3c10dd228daad9be3ea381c2f8b1e07e524fae6f + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_boolean.c - <_3:checksum rdf:nodeID="NukVOfZA342"/> - - + <_3:checksumValue>61db5ef1604240b33fa9e1e8825ad588076a5aef - <_3:checksumValue>fb4f806e7282dd3cb2df04e228672d8b0b1b8eb4 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_error_misc.c - <_3:checksum rdf:nodeID="NukVOfZA316"/> - - + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP366"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_error.c - <_3:checksum rdf:nodeID="NukVOfZA176"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hobject_enum.c - <_3:checksum rdf:nodeID="NukVOfZA194"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/guide/README.rst - <_3:checksum rdf:nodeID="NukVOfZA118"/> - - - - <_3:checksumValue>2e9dca0919a92c68ed30593292b3fe7140480062 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_strings.h - <_3:checksum rdf:nodeID="NukVOfZA378"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/codepage-conv/test.c - <_3:checksum rdf:nodeID="NukVOfZA76"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./Makefile.codepage - <_3:checksum rdf:nodeID="NukVOfZA22"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/dummy-date-provider/dummy_date_provider.c - <_3:checksum rdf:nodeID="NukVOfZA112"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./config/genconfig.py - <_3:checksum rdf:nodeID="NukVOfZA438"/> - - - - <_3:checksumValue>dfaa38c7372de482fd12634e4a3507f46e467e0f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>982e40839854be361e3b57b5c07ef4f710ab749b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>0811e545a133c3a62672e239624a0c1f11478b8d - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>0fd79121cfa729c2dd3e47632ec46204609013ef - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/jxpretty/README.rst - <_3:checksum rdf:nodeID="NukVOfZA80"/> - - - - <_3:checksumValue>f9072f5c361c86887b57ce662b3cd7211b4ce346 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/alloc-torture/README.rst - <_3:checksum rdf:nodeID="NukVOfZA132"/> - - - - <_3:checksumValue>d49c1cdb51b3a4fdd823c13831617a1f0a93edd1 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heap_stringcache.c - <_3:checksum rdf:nodeID="NukVOfZA420"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_alloc_default.c - <_3:checksum rdf:nodeID="NukVOfZA418"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/cmdline/duk_cmdline.c - <_3:checksum rdf:nodeID="NukVOfZA144"/> - - - - <_3:checksumValue>506914e460ff9d7536f10efef54b24b83c390410 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_debugger.h - <_3:checksum rdf:nodeID="NukVOfZA364"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_heap.c - <_3:checksum rdf:nodeID="NukVOfZA290"/> - - - - <_3:checksumValue>1c45360bd50cff6c2c25087d52136b390179e8fc - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>bf522799f089bf27e5ef2196b73c7e3d294ee5ba - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_object.c - <_3:checksum rdf:nodeID="NukVOfZA400"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/poll.c - <_3:checksum rdf:nodeID="NukVOfZA104"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_buffer.c - <_3:checksum rdf:nodeID="NukVOfZA380"/> - - - - <_3:checksumValue>11a7a5b6b1557adeca8a9def51cb44282f24c853 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_error_longjmp.c - <_3:checksum rdf:nodeID="NukVOfZA254"/> - - - - <_3:checksumValue>8aa63b553757fe1229638e978b540d7116b70274 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>23b6b54a8a35fbec735ffb332f4100a7f00557be - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_lexer.c - <_3:checksum rdf:nodeID="NukVOfZA228"/> - - - - <_3:checksumValue>61c7f89aa56094410418e766c89c1975db021daa - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>bf5a69136d03c3a573822dc1fe6e595a92c5d9b5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>4d3413b7b28775afc4a5be95e91208fab25b02f3 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_thrower.c - <_3:checksum rdf:nodeID="NukVOfZA338"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_internal.h - <_3:checksum rdf:nodeID="NukVOfZA260"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_numconv.c - <_3:checksum rdf:nodeID="NukVOfZA382"/> - - - - <_3:checksumValue>76fafefbb89d1d3561a44bf6c253415ab86633f7 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_error_throw.c - <_3:checksum rdf:nodeID="NukVOfZA178"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./debugger/static/index.html - <_3:checksum rdf:nodeID="NukVOfZA54"/> - - - - <_3:checksumValue>d8fe87c8e0d17bd6977bbc34d562e4b79c06f1a3 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>3a4934f863facf317ffcc1a6ce1d8f17ac658f38 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./LICENSE.txt - <_3:checksum rdf:nodeID="NukVOfZA8"/> - - - - <_3:checksumValue>24a2346fa389c2294cc0e96427e0bd206dac10b9 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_util_tinyrandom.c - <_3:checksum rdf:nodeID="NukVOfZA280"/> - - - - <_3:checksumValue>4239a907720cf3620bd0b03eb43981e7182e305a - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>578b63fa72c87e894a47a9f82102ecee895f932f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>628eded8d5c2a48cb32a615bb7f11f164c949540 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heaphdr.h - <_3:checksum rdf:nodeID="NukVOfZA386"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_bytecode.c - <_3:checksum rdf:nodeID="NukVOfZA328"/> - - - - <_3:checksumValue>742635fda10ef9775864077e647b59442768a69c - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src/duktape.c - <_3:checksum rdf:nodeID="NukVOfZA452"/> - - - - <_3:checksumValue>533dd2148cf54628be701ce5bbbda88c443244fd - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/alloc-torture/duk_alloc_torture.c - <_3:checksum rdf:nodeID="NukVOfZA134"/> - - - - <_3:checksumValue>439430cb950965d418b5bcb4ca36047f77a26a7c - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>925915ad11fea8da4582dbd9bc9e8b5ffbb8994d - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_js_compiler.h - <_3:checksum rdf:nodeID="NukVOfZA300"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/fileio.c - <_3:checksum rdf:nodeID="NukVOfZA96"/> - - - - <_3:checksumValue>c2a8bb08084e49f0e12d31562a90f72046761028 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>bce447cad4609861c4db6edbfe38bf2fa150e651 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>2321e0a68bf940f8346d00adda9e4a58fa51f608 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>839ade6f7b93fd0fc604e3e0934568331eedd648 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>a9206a7b46f8d8319b798475650217f494fa76ab - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/alloc-hybrid/duk_alloc_hybrid.h - <_3:checksum rdf:nodeID="NukVOfZA66"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_strings.c - <_3:checksum rdf:nodeID="NukVOfZA220"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_math.c - <_3:checksum rdf:nodeID="NukVOfZA264"/> - - - - <_3:checksumValue>0125ebcabe62cef4923e75527d3128e8c48cdf1f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>bfbf3b8ea996451740a7ad2d8d1376feca4ca382 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_codec.c - <_3:checksum rdf:nodeID="NukVOfZA356"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./polyfills/object-prototype-definesetter.js - <_3:checksum rdf:nodeID="NukVOfZA430"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/sandbox/sandbox.c - <_3:checksum rdf:nodeID="NukVOfZA164"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/socket.c - <_3:checksum rdf:nodeID="NukVOfZA90"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_buffer.c - <_3:checksum rdf:nodeID="NukVOfZA302"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hthread_stacks.c - <_3:checksum rdf:nodeID="NukVOfZA292"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./Makefile.cmdline - <_3:checksum rdf:nodeID="NukVOfZA18"/> - - - - <_3:checksumValue>4db4ca2d7ce3f076fd195372d53e8bc5714d2597 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>813eed354904f72d97568c814fbcf5fffbb62d12 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/alloc-logging/duk_alloc_logging.h - <_3:checksum rdf:nodeID="NukVOfZA172"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hnativefunction.h - <_3:checksum rdf:nodeID="NukVOfZA294"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/guide/processlines.c - <_3:checksum rdf:nodeID="NukVOfZA120"/> - - - - <_3:checksumValue>c000aebe8b6794338529fdf6e02c0cfdcf4d2dfc - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>2c508fbc7eb127f6793cfe62bf947879668983a4 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./debugger/README.rst - <_3:checksum rdf:nodeID="NukVOfZA38"/> - - - - <_3:checksumValue>b4c9666ce152c9a98bf965aae4ef4fe0b36b2130 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>b4d00dadc78f1ac25d87d8d7a48fd67161235d4f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_debug_heap.c - <_3:checksum rdf:nodeID="NukVOfZA414"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_js_var.c - <_3:checksum rdf:nodeID="NukVOfZA314"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/debug-trans-socket/README.rst - <_3:checksum rdf:nodeID="NukVOfZA150"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> <_3:fileName>./src-separate/duk_debug.h - <_3:checksum rdf:nodeID="NukVOfZA340"/> + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - - <_3:checksumValue>6988aac432dcc185c2967732e21947ea0696377f + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>52554f56c3e3420d3643aa22f563d32a2b18be1f + - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP324"/> + + <_3:fileName>./src-separate/duk_hbufferobject_misc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP442"/> + + <_3:fileName>./src-separate/duk_debug_fixedbuffer.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>fb4f806e7282dd3cb2df04e228672d8b0b1b8eb4 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP290"/> + + <_3:fileName>./src-separate/duk_heap_misc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP384"/> + + <_3:fileName>./src-separate/duk_api_compile.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>422984e8fc919e9f8c64d5cc4b20d7f6d15e341b + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP278"/> + + <_3:fileName>./src-separate/duk_error_longjmp.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>d0421b2e96d2365467764d4aecc442fe543d69ad + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>1db75c875cb94e1317f095e3d78f11275c17d154 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP138"/> + + <_3:fileName>./examples/cpp-exceptions/cpp_exceptions.cpp <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./licenses/commonjs.txt - <_3:checksum rdf:nodeID="NukVOfZA448"/> - - - <_3:checksumValue>878e91bed3a8756c70aaa43bb1566040fe6e42f0 + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hstring.h - <_3:checksum rdf:nodeID="NukVOfZA256"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_json.c - <_3:checksum rdf:nodeID="NukVOfZA268"/> - - - - <_3:checksumValue>e023af5c2fb4b1efab74a230c552f1eb1b37fc10 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>e44b8b092afcfa97e693eb3e0be97d41f8aff301 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>2eadae5af69aec5e3336b6a869fe64771d4db080 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>935644ce5c2bcd1f9b725c742a91dd34ec7c7fc3 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>13d0e469fd05cef5066b33ad1310658e4cf5c7c8 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>f1dee4b05f535519fbf3662469c2ce810b6e2545 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_tval.h - <_3:checksum rdf:nodeID="NukVOfZA332"/> - - - - <_3:checksumValue>635d4642c9ecd5fd9a5346bf9f0e38db102b09b6 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>7502f77b459c82f4e9a45ecdde05125d79153bdf - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>042bfc66d9b0f01ce8075818959c9a72c35b4bb4 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./polyfills/object-assign.js - <_3:checksum rdf:nodeID="NukVOfZA428"/> - - - - <_3:checksumValue>5e8812e8226d2ec0387af6e2ce9565755e274164 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>56a4e5fbd50d1b9917625a0dfcf6e2619b034786 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>8015d14ffbc7a4a4b93d654f093aa48ec17fce4e - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>73ff75213f392b6125c68ab6b430176dfad71269 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>a20231719c1f9b97ea38fbc42dd8af1e21d74879 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heap_memory.c - <_3:checksum rdf:nodeID="NukVOfZA368"/> - - - - <_3:checksumValue>949e147e9b5e284590449d0e8f74427c8c12f00f - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hthread_misc.c - <_3:checksum rdf:nodeID="NukVOfZA210"/> - - - - <_3:checksumValue>c1036bb5992816ffb09e8b2ee24f082a881326e9 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_js.h - <_3:checksum rdf:nodeID="NukVOfZA212"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/coffee/globals.coffee - <_3:checksum rdf:nodeID="NukVOfZA64"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_error_augment.c - <_3:checksum rdf:nodeID="NukVOfZA288"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hthread.h - <_3:checksum rdf:nodeID="NukVOfZA320"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/hello/hello.c - <_3:checksum rdf:nodeID="NukVOfZA138"/> - - - - <_3:checksumValue>af6b0cd61c02efa575b9106682606297d26f013b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>57f519aabc8730f19d197bd00fe7e4f592063ddf - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./polyfills/console-minimal.js - <_3:checksum rdf:nodeID="NukVOfZA434"/> - - - - <_3:checksumValue>1e6c5c99fdcef26a561724faa703bf9c53c73bca - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_string.c - <_3:checksum rdf:nodeID="NukVOfZA242"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_logging.c - <_3:checksum rdf:nodeID="NukVOfZA262"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/basic-test.js - <_3:checksum rdf:nodeID="NukVOfZA102"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_regexp.h - <_3:checksum rdf:nodeID="NukVOfZA236"/> - - - - <_3:checksumValue>12da70c807ea25465e5e0191784203ff6a1c7d0c - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>10c24a17c2f5f82d8c1a8fab8673c0c9075c1817 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/dummy-date-provider/README.rst - <_3:checksum rdf:nodeID="NukVOfZA110"/> - - - - <_3:checksumValue>b2f66f393c178e011c068b230f17ef8a48b4ee29 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_heap.h - <_3:checksum rdf:nodeID="NukVOfZA232"/> - - - - <_3:checksumValue>0aee8a99ab7468ae7254d0b19f898a7c67f24c4d - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>22046b9dfc552ed692193d1bf5e3d0e182111ae5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_date_unix.c - <_3:checksum rdf:nodeID="NukVOfZA204"/> - - - - <_3:checksumValue>149fd21526c90d52b22e77b297f76e6da3e656ff - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./debugger/Makefile - <_3:checksum rdf:nodeID="NukVOfZA40"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_error_macros.c - <_3:checksum rdf:nodeID="NukVOfZA344"/> - - - - <_3:checksumValue>c8ae046bda2c920b5d807dfa68c8159b655b0873 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>3e4c09bd49dbe5d8509da6f2387eadfca945126c - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>b381ea15009eb8140c0789203345cdcc2c6c1cd6 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/guide/primecheck.c - <_3:checksum rdf:nodeID="NukVOfZA128"/> - - - - <_3:checksumValue>f79f6933571dcdd7108447f6e8e86f4735b30caf - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>5583c0190c2038be60ba2de07d155d5077defb03 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/codepage-conv/README.rst - <_3:checksum rdf:nodeID="NukVOfZA72"/> - - - - <_3:checksumValue>a1b146201fb105044a9922781e22d14bcbd5584c - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>5d593ae6316ed7a3ea6e7ed0a47267745d79d12d - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>136f423bdc27f3effc1e45c44327c1d3ef82f0d9 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>bf80565339b6d9eb92f7e8b35420317cf00392f1 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hobject_alloc.c - <_3:checksum rdf:nodeID="NukVOfZA238"/> - - - - <_3:checksumValue>36b07bc32cf613c091d5e4261cbe44b0556704fd - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>01138dd2786346a159c06e43f094d07f002df881 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/hello/README.rst - <_3:checksum rdf:nodeID="NukVOfZA140"/> - - - - <_3:checksumValue>edc510f4b2921d24eb9bc37ee0dd4a3d42743083 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./debugger/duk_debugcommands.yaml - <_3:checksum rdf:nodeID="NukVOfZA42"/> - - - - <_3:checksumValue>88ab1d060886393d94b6fb7c6054a0189117340b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hbuffer_ops.c - <_3:checksum rdf:nodeID="NukVOfZA348"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_protos.h - <_3:checksum rdf:nodeID="NukVOfZA274"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_util_bitencoder.c - <_3:checksum rdf:nodeID="NukVOfZA362"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hobject_props.c - <_3:checksum rdf:nodeID="NukVOfZA224"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./licenses/murmurhash2.txt - <_3:checksum rdf:nodeID="NukVOfZA446"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./debugger/duk_classnames.yaml - <_3:checksum rdf:nodeID="NukVOfZA46"/> - - - - <_3:checksumValue>f396c6aec456b183ef77e33da1dfffc89c417056 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - <_3:checksumValue>23575db7cd88e42c0c3fc1630f44bf608fcec76d - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - <_3:checksumValue>b0916311103fdea3fd5bbf76a99748a3d21a5486 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - <_3:checksumValue>1c40a52fd54baf7ac334fce4829892d5d951401a - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>83b27494e6b257ab09828b0a4a1cf907686778a5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./Makefile.hello - <_3:checksum rdf:nodeID="NukVOfZA14"/> - - - - <_3:checksumValue>71d2f9df7bf793f80f3cd6080c986a437f9b2991 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/README.rst - <_3:checksum rdf:nodeID="NukVOfZA56"/> - - - - <_3:checksumValue>c8d7674f8215d515779d2cfaf61105c4d2fd5eb5 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>8c5ee5b508a23ac5089a7e6c76593b6678965869 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP272"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/debug-trans-dvalue/test.c - <_3:checksum rdf:nodeID="NukVOfZA162"/> - - - - <_3:checksumValue>d45e3fc443887261ce432a807aaebd2a1812264e - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>57f519aabc8730f19d197bd00fe7e4f592063ddf - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_bi_logger.c - <_3:checksum rdf:nodeID="NukVOfZA276"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/debug-trans-dvalue/duk_trans_dvalue.h - <_3:checksum rdf:nodeID="NukVOfZA154"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/cmdline/duk_cmdline_ajduk.c - <_3:checksum rdf:nodeID="NukVOfZA142"/> - - - - <_3:checksumValue>ba20a4d987de1eef311c99f21db6621cb4b1a5d1 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hbufferobject.h - <_3:checksum rdf:nodeID="NukVOfZA370"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_api_object.c - <_3:checksum rdf:nodeID="NukVOfZA324"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/debug-trans-socket/duk_trans_socket.c - <_3:checksum rdf:nodeID="NukVOfZA152"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - <_3:fileName>./examples/sandbox/README.rst - <_3:checksum rdf:nodeID="NukVOfZA166"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hobject_finalizer.c - <_3:checksum rdf:nodeID="NukVOfZA216"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/guide/process.js - <_3:checksum rdf:nodeID="NukVOfZA126"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/eventloop/c_eventloop.c - <_3:checksum rdf:nodeID="NukVOfZA92"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_unicode_support.c - <_3:checksum rdf:nodeID="NukVOfZA180"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_util_hashprime.c - <_3:checksum rdf:nodeID="NukVOfZA284"/> - - - - <_3:checksumValue>37e22b43351b7f0518b7fbb9e5c109d7a53a31e7 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>fb9c2ff459fd84b4587f846fbd36219cf8f06931 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>d529a6faac560def1e5b2cdb991713a6d70b0e26 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>f3ed5c785b60b0f39a74cc3f5b73b0c6e24287c3 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>34b0dc439c1aeb920a1db0ac0ed20ee189069ea1 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>111a7b97b46f038bd7f0f260ef5c9ff66c057217 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_hobject_class.c - <_3:checksum rdf:nodeID="NukVOfZA272"/> - - - - <_3:checksumValue>ed3bd07dbd103d285277ab38c4b4a7dd4a4b654b - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> <_3:fileName>./src-separate/duk_builtins.c - <_3:checksum rdf:nodeID="NukVOfZA248"/> - - - - <_3:checksumValue>6fec920096ab278342b4832aac85e480f47c3b69 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>767b33200578243befc9b2b6b4a579dc3784f748 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>84b3f74e55ed4d76634e144d668601480573b369 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./examples/codepage-conv/duk_codepage_conv.c - <_3:checksum rdf:nodeID="NukVOfZA74"/> - - - <_3:checksumValue>6f12665affb325d53ab11c0e40418b2326c1ac17 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:checksumValue>2b7443b734ad4f6e53e2f35e5aff74464410a680 - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - - - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:copyrightText>Copyright 2013-2014 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP418"/> + + <_3:fileName>./src-separate/duk_api_string.c <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - <_3:fileName>./src-separate/duk_error.h - <_3:checksum rdf:nodeID="NukVOfZA198"/> - - - <_3:checksumValue>a2896c39c83a21a2f79d0c4babd5012d85873116 + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP332"/> + + <_3:fileName>./src-separate/duk_lexer.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP328"/> + + <_3:fileName>./src-separate/duk_bi_buffer.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - + <_3:checksumValue>97bf0ab32255874def0bd3157bf4bb2fc731d37f - <_3:checksumValue>3c8a488f2b4195d33379874172ae6d8b74beaa58 + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP148"/> + + <_3:fileName>./examples/guide/process.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - + <_3:checksumValue>0811e545a133c3a62672e239624a0c1f11478b8d - <_3:checksumValue>d535c4e27319a5db6026553a801e8a5ef0e6fe88 + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - + <_3:checksumValue>742d035afe3ae16b3498926494419b74c53dfaf4 - <_3:checksumValue>4baffeb2aa785bdc1065eb9ddb8c64c8a028655d + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - - + <_3:checksumValue>34b0dc439c1aeb920a1db0ac0ed20ee189069ea1 + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP440"/> + + <_3:fileName>./src-separate/duk_debug_heap.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP210"/> + + <_3:fileName>./src-separate/duk_util_bufwriter.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP32"/> + + <_3:fileName>./Makefile.eval + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>221600498f2801d0bfc71e36009f084f363e159e + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP444"/> + + <_3:fileName>./src-separate/duk_alloc_default.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>bad7c737fdd2d5f21ac00c6936921184cd26908d + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>21e33f2c348ab084c0869d3bba530b1885464f38 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP70"/> + + <_3:fileName>./debugger/static/webui.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP350"/> + + <_3:fileName>./src-separate/duk_api_object.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP280"/> + + <_3:fileName>./src-separate/duk_hstring.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP218"/> + + <_3:fileName>./src-separate/duk_hobject_enum.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>525e80da2b6d3640fd42af0f662d7b68865d6529 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>84b33d737bba2dadfdd950adad7a96d3d88eb01d + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP54"/> + + <_3:fileName>./debugger/Makefile + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP106"/> + + <_3:fileName>./examples/eventloop/ncurses.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP342"/> + + <_3:fileName>./src-separate/duk_error_misc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>012bd42371c53e6c32e357201ee91c258640e546 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP254"/> + + <_3:fileName>./src-separate/duk_js_bytecode.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP134"/> + + <_3:fileName>./examples/eval/eval.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP306"/> + + <_3:fileName>./src-separate/duk_util_tinyrandom.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP170"/> + + <_3:fileName>./examples/debug-trans-socket/duk_trans_socket_windows.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP264"/> + + <_3:fileName>./src-separate/duk_forwdecl.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP352"/> + + <_3:fileName>./src-separate/duk_hbuffer.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a5985c22d5e36eaced8ebc72338a38ae0b73c9ad + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP104"/> + + <_3:fileName>./examples/eventloop/c_eventloop.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP484"/> + + <_3:fileName>./licenses/commonjs.txt + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP488"/> + + <_3:fileName>./src/duk_config.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4edee4bb513bcff807e343902af260ed8ff72850 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP424"/> + + <_3:fileName>./src-separate/duk_tval.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>5e427d4685c63b3e7c638c6eaac5e7df8216507f + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP108"/> + + <_3:fileName>./examples/eventloop/socket.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP166"/> + + <_3:fileName>./examples/cmdline/duk_cmdline.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP356"/> + + <_3:fileName>./src-separate/duk_selftest.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP256"/> + + <_3:fileName>./src-separate/duk_heap.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP190"/> + + <_3:fileName>./examples/sandbox/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP374"/> + + <_3:fileName>./src-separate/duk_hbuffer_ops.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>11a7a5b6b1557adeca8a9def51cb44282f24c853 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP340"/> + + <_3:fileName>./src-separate/duk_js_var.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP248"/> + + <_3:fileName>./src-separate/duk_hobject_props.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP376"/> + + <_3:fileName>./src-separate/duk_heap_hashstring.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>2e1b55e44a5845fb785dde5b8c2e24bb7bd2e1bf + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a98ed9095834cad5b50d63cf8e659cca90e01062 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP228"/> + + <_3:fileName>./src-separate/duk_bi_date_unix.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>467388c812411a0d2b80760983171c346d35953d + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP372"/> + + <_3:fileName>./src-separate/duk_regexp_compiler.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4d3ab8c2d41261b0cae627db9d536d26f72b5f8e + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP460"/> + + <_3:fileName>./polyfills/object-prototype-definesetter.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>79dac8ea1aa08daa3c8e9b6137b8a01c8d501893 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>8aa63b553757fe1229638e978b540d7116b70274 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP326"/> + + <_3:fileName>./src-separate/duk_js_compiler.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>32ba21f45afd4b027113eda5aba53314c3f00da9 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP46"/> + + <_3:fileName>./debugger/duk_debug.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>c00100a35037a372ebcde740082d5bb7c7735057 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP136"/> + + <_3:fileName>./examples/cpp-exceptions/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP486"/> + + <_3:fileName>./src/metadata.json + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>5bd828887b0f46810358539868398e64b622d047 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>82314b509ee3b15b393fefe747c8e0169ab39aaa + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP408"/> + + <_3:fileName>./src-separate/duk_numconv.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP270"/> + + <_3:fileName>./src-separate/duk_bi_date.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>23b6b54a8a35fbec735ffb332f4100a7f00557be + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP346"/> + + <_3:fileName>./src-separate/duk_hthread.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP58"/> + + <_3:fileName>./debugger/duk_debug_meta.json + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>fe251e819feb6f84c1c8169eb6921174be2b1373 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>6806426efc13e73e41899bef0aecca7eec097c18 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP434"/> + + <_3:fileName>./src-separate/duktape.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP40"/> + + <_3:fileName>./src-noline/duk_config.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP450"/> + + <_3:fileName>./src-separate/duk_debug_macros.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>012eed9a677efd2062f7ed6965d5a39e9e569c25 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>8015d14ffbc7a4a4b93d654f093aa48ec17fce4e + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP118"/> + + <_3:fileName>./examples/eventloop/curses-timers.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>fa2824f02d8a2d21f729a4e9d44557f3b39a9355 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP404"/> + + <_3:fileName>./src-separate/duk_strings.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP184"/> + + <_3:fileName>./examples/debug-trans-dvalue/duk_trans_dvalue.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a8c0b54002a3a7d8c69d385e7fbcf4b70d1efc70 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>c81b68018e3d6f1b93683f7ead8761c01f2ca760 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP446"/> + + <_3:fileName>./src-separate/duk_heap_stringcache.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>df02f8688766b929639cca4881b73cb8f745c97c + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP336"/> + + <_3:fileName>./src-separate/duk_heap_refcount.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>59df770184e4c26b190a76f4cd035c7e661d573f + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP470"/> + + <_3:fileName>./config/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>fd24ca07cfd8fd37f3e70d10ad078ee5f149c9ce + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP30"/> + + <_3:fileName>./Makefile.dukdebug + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP436"/> + + <_3:fileName>./src-separate/duk_replacements.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>22046b9dfc552ed692193d1bf5e3d0e182111ae5 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP284"/> + + <_3:fileName>./src-separate/duk_api_internal.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP400"/> + + <_3:fileName>./src-separate/duk_js_executor.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP482"/> + + <_3:fileName>./licenses/lua.txt + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>e023af5c2fb4b1efab74a230c552f1eb1b37fc10 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP128"/> + + <_3:fileName>./examples/dummy-date-provider/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>54a05944602f4a24864001a40d770591c6800daf + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4e41e7165a8d6e3bd370bc4536b16835a7204cf6 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a23d89e3ff8fe247e09338af7b38bdab41da5c3e + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP358"/> + + <_3:fileName>./src-separate/duk_tval.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>821b268a1d4339ea2b309bdb6f527aa61bdb6b23 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>194e0bf80a1ddcc4d2d68ea6d2539656f3044f78 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>063133679b6d072efc1c27f3a510101744ffde0c + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP354"/> + + <_3:fileName>./src-separate/duk_api_bytecode.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>5f3b6cd81be97aa687fe8b47751e68b5561d7c1b + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ad583b87e72c08b4b44918dd1d7fce97e4950aa4 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>7e2674dd72227576375a80f6ddbb11320f5b987a + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>83b27494e6b257ab09828b0a4a1cf907686778a5 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP368"/> + + <_3:fileName>./src-separate/duk_bi_boolean.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>829c4239ff43a1e15aa08bbbab41e7fba9207859 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP126"/> + + <_3:fileName>./examples/eventloop/server-socket-test.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a913f60f44a9e19cd5c31e84242db88a0868eba8 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP144"/> + + <_3:fileName>./examples/guide/uppercase.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>786369a33cccbadc3d2efba613a43fdd638971fc + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP220"/> + + <_3:fileName>./src-separate/duk_api_debug.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>881f1b114c9fbba139044ddcbbc5398243185d10 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP64"/> + + <_3:fileName>./debugger/duk_opcodes.yaml + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>3fa5d72893eb3e1d42d07c8effc8bb1443f87dd6 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>105dd2e79d90b96b6b1ae419bff31ed6a0273af6 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>48eafa3f368fc879bfb79c2b2a30846a0b5d9b42 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>3f2b3b6b16cc969631b9980bc67aa6cc2c872048 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP314"/> + + <_3:fileName>./src-separate/duk_error_augment.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP364"/> + + <_3:fileName>./src-separate/duk_bi_thrower.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>6b98824e13a3d9536542b8da51d012a3d66ceec1 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>23f0401f57af7b8e4df6636637caffce6956445b + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP162"/> + + <_3:fileName>./examples/hello/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>457df68e290e23da40cac39a7cc35d6d6b4257c6 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP62"/> + + <_3:fileName>./debugger/duk_classnames.yaml + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a4e2dfaee71b2316f2c3d149b4a507250b54dd96 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP214"/> + + <_3:fileName>./src-separate/duk_jmpbuf.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>089c395fca3cedceec09fd38d32d0c77dc8658f4 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>3f640daaa5e9d226a04fe419cb5eb1c07d06d346 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP48"/> + + <_3:fileName>./debugger/duk_debugerrors.yaml + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP370"/> + + <_3:fileName>./src-separate/duk_error_macros.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4239a907720cf3620bd0b03eb43981e7182e305a + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP294"/> + + <_3:fileName>./src-separate/duk_hthread_builtins.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP76"/> + + <_3:fileName>./examples/coffee/mandel.coffee + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>6988aac432dcc185c2967732e21947ea0696377f + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>7b167c1ea560de7ac67e217c1fdff8912f8b677d + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>521f29841ddeb9be08ff9f7e2db06277da31bd47 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP156"/> + + <_3:fileName>./examples/alloc-torture/duk_alloc_torture.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP158"/> + + <_3:fileName>./examples/alloc-torture/duk_alloc_torture.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP72"/> + + <_3:fileName>./debugger/static/index.html + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>93e24d8abbf79fb6a2fcd54679c476866ad6ab2a + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:sourceInfo>Official duktape.org release built from GitHub repo https://github.com/svaarala/duktape. + <_3:downloadLocation rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">http://duktape.org/duktape-1.5.2.tar.xz + <_3:licenseDeclared rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:supplier>Organization: duktape.org + <_3:packageVerificationCode rdf:nodeID="svBMzJkP5"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + <_3:description>Duktape is an embeddable Javascript engine, with a focus on portability and compact footprint + <_3:licenseComments>Duktape is copyrighted by its authors and licensed under the MIT license. MurmurHash2 is used internally, it is also under the MIT license. Duktape module loader is based on the CommonJS module loading specification (without sharing any code), CommonJS is under the MIT license. + <_3:originator>Organization: duktape.org + <_3:hasFile rdf:nodeID="svBMzJkP127"/> + <_3:hasFile rdf:nodeID="svBMzJkP101"/> + <_3:hasFile rdf:nodeID="svBMzJkP21"/> + <_3:hasFile rdf:nodeID="svBMzJkP337"/> + <_3:hasFile rdf:nodeID="svBMzJkP55"/> + <_3:hasFile rdf:nodeID="svBMzJkP91"/> + <_3:hasFile rdf:nodeID="svBMzJkP413"/> + <_3:hasFile rdf:nodeID="svBMzJkP321"/> + <_3:hasFile rdf:nodeID="svBMzJkP129"/> + <_3:hasFile rdf:nodeID="svBMzJkP139"/> + <_3:hasFile rdf:nodeID="svBMzJkP473"/> + <_3:hasFile rdf:nodeID="svBMzJkP357"/> + <_3:hasFile rdf:nodeID="svBMzJkP419"/> + <_3:hasFile rdf:nodeID="svBMzJkP451"/> + <_3:hasFile rdf:nodeID="svBMzJkP95"/> + <_3:hasFile rdf:nodeID="svBMzJkP115"/> + <_3:hasFile rdf:nodeID="svBMzJkP79"/> + <_3:hasFile rdf:nodeID="svBMzJkP275"/> + <_3:hasFile rdf:nodeID="svBMzJkP191"/> + <_3:hasFile rdf:nodeID="svBMzJkP261"/> + <_3:hasFile rdf:nodeID="svBMzJkP23"/> + <_3:hasFile rdf:nodeID="svBMzJkP353"/> + <_3:hasFile rdf:nodeID="svBMzJkP267"/> + <_3:hasFile rdf:nodeID="svBMzJkP427"/> + <_3:hasFile rdf:nodeID="svBMzJkP119"/> + <_3:hasFile rdf:nodeID="svBMzJkP205"/> + <_3:hasFile rdf:nodeID="svBMzJkP335"/> + <_3:hasFile rdf:nodeID="svBMzJkP211"/> + <_3:hasFile rdf:nodeID="svBMzJkP19"/> + <_3:hasFile rdf:nodeID="svBMzJkP149"/> + <_3:hasFile rdf:nodeID="svBMzJkP319"/> + <_3:hasFile rdf:nodeID="svBMzJkP367"/> + <_3:hasFile rdf:nodeID="svBMzJkP265"/> + <_3:hasFile rdf:nodeID="svBMzJkP441"/> + <_3:hasFile rdf:nodeID="svBMzJkP385"/> + <_3:hasFile rdf:nodeID="svBMzJkP289"/> + <_3:hasFile rdf:nodeID="svBMzJkP175"/> + <_3:hasFile rdf:nodeID="svBMzJkP277"/> + <_3:hasFile rdf:nodeID="svBMzJkP125"/> + <_3:hasFile rdf:nodeID="svBMzJkP471"/> + <_3:hasFile rdf:nodeID="svBMzJkP229"/> + <_3:hasFile rdf:nodeID="svBMzJkP143"/> + <_3:hasFile rdf:nodeID="svBMzJkP415"/> + <_3:hasFile rdf:nodeID="svBMzJkP137"/> + <_3:hasFile rdf:nodeID="svBMzJkP219"/> + <_3:hasFile rdf:nodeID="svBMzJkP37"/> + <_3:hasFile rdf:nodeID="svBMzJkP429"/> + <_3:hasFile rdf:nodeID="svBMzJkP485"/> + <_3:hasFile rdf:nodeID="svBMzJkP63"/> + <_3:hasFile rdf:nodeID="svBMzJkP295"/> + <_3:hasFile rdf:nodeID="svBMzJkP301"/> + <_3:hasFile rdf:nodeID="svBMzJkP231"/> + <_3:hasFile rdf:nodeID="svBMzJkP89"/> + <_3:hasFile rdf:nodeID="svBMzJkP35"/> + <_3:hasFile rdf:nodeID="svBMzJkP349"/> + <_3:hasFile rdf:nodeID="svBMzJkP297"/> + <_3:hasFile rdf:nodeID="svBMzJkP271"/> + <_3:hasFile rdf:nodeID="svBMzJkP171"/> + <_3:hasFile rdf:nodeID="svBMzJkP467"/> + <_3:hasFile rdf:nodeID="svBMzJkP393"/> + <_3:hasFile rdf:nodeID="svBMzJkP417"/> + <_3:hasFile rdf:nodeID="svBMzJkP331"/> + <_3:hasFile rdf:nodeID="svBMzJkP291"/> + <_3:hasFile rdf:nodeID="svBMzJkP185"/> + <_3:hasFile rdf:nodeID="svBMzJkP327"/> + <_3:hasFile rdf:nodeID="svBMzJkP313"/> + <_3:hasFile rdf:nodeID="svBMzJkP147"/> + <_3:hasFile rdf:nodeID="svBMzJkP363"/> + <_3:hasFile rdf:nodeID="svBMzJkP97"/> + <_3:hasFile rdf:nodeID="svBMzJkP49"/> + <_3:hasFile rdf:nodeID="svBMzJkP409"/> + <_3:hasFile rdf:nodeID="svBMzJkP41"/> + <_3:hasFile rdf:nodeID="svBMzJkP243"/> + <_3:hasFile rdf:nodeID="svBMzJkP151"/> + <_3:hasFile rdf:nodeID="svBMzJkP439"/> + <_3:hasFile rdf:nodeID="svBMzJkP213"/> + <_3:hasFile rdf:nodeID="svBMzJkP379"/> + <_3:hasFile rdf:nodeID="svBMzJkP131"/> + <_3:hasFile rdf:nodeID="svBMzJkP333"/> + <_3:hasFile rdf:nodeID="svBMzJkP47"/> + <_3:hasFile rdf:nodeID="svBMzJkP369"/> + <_3:hasFile rdf:nodeID="svBMzJkP209"/> + <_3:hasFile rdf:nodeID="svBMzJkP273"/> + <_3:hasFile rdf:nodeID="svBMzJkP31"/> + <_3:hasFile rdf:nodeID="svBMzJkP73"/> + <_3:hasFile rdf:nodeID="svBMzJkP293"/> + <_3:hasFile rdf:nodeID="svBMzJkP389"/> + <_3:hasFile rdf:nodeID="svBMzJkP27"/> + <_3:hasFile rdf:nodeID="svBMzJkP281"/> + <_3:hasFile rdf:nodeID="svBMzJkP259"/> + <_3:hasFile rdf:nodeID="svBMzJkP75"/> + <_3:hasFile rdf:nodeID="svBMzJkP443"/> + <_3:hasFile rdf:nodeID="svBMzJkP287"/> + <_3:hasFile rdf:nodeID="svBMzJkP383"/> + <_3:hasFile rdf:nodeID="svBMzJkP317"/> + <_3:hasFile rdf:nodeID="svBMzJkP69"/> + <_3:hasFile rdf:nodeID="svBMzJkP155"/> + <_3:hasFile rdf:nodeID="svBMzJkP157"/> + <_3:hasFile rdf:nodeID="svBMzJkP279"/> + <_3:hasFile rdf:nodeID="svBMzJkP215"/> + <_3:hasFile rdf:nodeID="svBMzJkP217"/> + <_3:hasFile rdf:nodeID="svBMzJkP71"/> + <_3:hasFile rdf:nodeID="svBMzJkP83"/> + <_3:hasFile rdf:nodeID="svBMzJkP199"/> + <_3:hasFile rdf:nodeID="svBMzJkP53"/> + <_3:hasFile rdf:nodeID="svBMzJkP105"/> + <_3:hasFile rdf:nodeID="svBMzJkP341"/> + <_3:hasFile rdf:nodeID="svBMzJkP195"/> + <_3:hasFile rdf:nodeID="svBMzJkP347"/> + <_3:hasFile rdf:nodeID="svBMzJkP253"/> + <_3:hasFile rdf:nodeID="svBMzJkP133"/> + <_3:hasFile rdf:nodeID="svBMzJkP305"/> + <_3:hasFile rdf:nodeID="svBMzJkP169"/> + <_3:hasFile rdf:nodeID="svBMzJkP465"/> + <_3:hasFile rdf:nodeID="svBMzJkP303"/> + <_3:hasFile rdf:nodeID="svBMzJkP187"/> + <_3:hasFile rdf:nodeID="svBMzJkP489"/> + <_3:hasFile rdf:nodeID="svBMzJkP351"/> + <_3:hasFile rdf:nodeID="svBMzJkP109"/> + <_3:hasFile rdf:nodeID="svBMzJkP103"/> + <_3:hasFile rdf:nodeID="svBMzJkP9"/> + <_3:hasFile rdf:nodeID="svBMzJkP17"/> + <_3:hasFile rdf:nodeID="svBMzJkP395"/> + <_3:hasFile rdf:nodeID="svBMzJkP381"/> + <_3:hasFile rdf:nodeID="svBMzJkP431"/> + <_3:hasFile rdf:nodeID="svBMzJkP343"/> + <_3:hasFile rdf:nodeID="svBMzJkP481"/> + <_3:hasFile rdf:nodeID="svBMzJkP251"/> + <_3:hasFile rdf:nodeID="svBMzJkP421"/> + <_3:hasFile rdf:nodeID="svBMzJkP189"/> + <_3:hasFile rdf:nodeID="svBMzJkP405"/> + <_3:hasFile rdf:nodeID="svBMzJkP299"/> + <_3:hasFile rdf:nodeID="svBMzJkP487"/> + <_3:hasFile rdf:nodeID="svBMzJkP93"/> + <_3:hasFile rdf:nodeID="svBMzJkP463"/> + <_3:hasFile rdf:nodeID="svBMzJkP67"/> + <_3:hasFile rdf:nodeID="svBMzJkP423"/> + <_3:hasFile rdf:nodeID="svBMzJkP329"/> + <_3:hasFile rdf:nodeID="svBMzJkP107"/> + <_3:hasFile rdf:nodeID="svBMzJkP165"/> + <_3:hasFile rdf:nodeID="svBMzJkP111"/> + <_3:hasFile rdf:nodeID="svBMzJkP355"/> + <_3:hasFile rdf:nodeID="svBMzJkP223"/> + <_3:hasFile rdf:nodeID="svBMzJkP483"/> + <_3:hasFile rdf:nodeID="svBMzJkP387"/> + <_3:hasFile rdf:nodeID="svBMzJkP255"/> + <_3:hasFile rdf:nodeID="svBMzJkP453"/> + <_3:hasFile rdf:nodeID="svBMzJkP391"/> + <_3:hasFile rdf:nodeID="svBMzJkP7"/> + <_3:hasFile rdf:nodeID="svBMzJkP249"/> + <_3:hasFile rdf:nodeID="svBMzJkP241"/> + <_3:hasFile rdf:nodeID="svBMzJkP197"/> + <_3:hasFile rdf:nodeID="svBMzJkP263"/> + <_3:hasFile rdf:nodeID="svBMzJkP177"/> + <_3:hasFile rdf:nodeID="svBMzJkP397"/> + <_3:hasFile rdf:nodeID="svBMzJkP245"/> + <_3:hasFile rdf:nodeID="svBMzJkP113"/> + <_3:hasFile rdf:nodeID="svBMzJkP475"/> + <_3:hasFile rdf:nodeID="svBMzJkP59"/> + <_3:hasFile rdf:nodeID="svBMzJkP247"/> + <_3:hasFile rdf:nodeID="svBMzJkP375"/> + <_3:hasFile rdf:nodeID="svBMzJkP437"/> + <_3:hasFile rdf:nodeID="svBMzJkP173"/> + <_3:hasFile rdf:nodeID="svBMzJkP163"/> + <_3:hasFile rdf:nodeID="svBMzJkP411"/> + <_3:hasFile rdf:nodeID="svBMzJkP373"/> + <_3:hasFile rdf:nodeID="svBMzJkP371"/> + <_3:hasFile rdf:nodeID="svBMzJkP65"/> + <_3:hasFile rdf:nodeID="svBMzJkP459"/> + <_3:hasFile rdf:nodeID="svBMzJkP461"/> + <_3:hasFile rdf:nodeID="svBMzJkP257"/> + <_3:hasFile rdf:nodeID="svBMzJkP325"/> + <_3:hasFile rdf:nodeID="svBMzJkP43"/> + <_3:hasFile rdf:nodeID="svBMzJkP45"/> + <_3:hasFile rdf:nodeID="svBMzJkP51"/> + <_3:hasFile rdf:nodeID="svBMzJkP457"/> + <_3:hasFile rdf:nodeID="svBMzJkP365"/> + <_3:hasFile rdf:nodeID="svBMzJkP167"/> + <_3:hasFile rdf:nodeID="svBMzJkP479"/> + <_3:hasFile rdf:nodeID="svBMzJkP233"/> + <_3:hasFile rdf:nodeID="svBMzJkP135"/> + <_3:hasFile rdf:nodeID="svBMzJkP377"/> + <_3:hasFile rdf:nodeID="svBMzJkP309"/> + <_3:hasFile rdf:nodeID="svBMzJkP235"/> + <_3:hasFile rdf:nodeID="svBMzJkP207"/> + <_3:hasFile rdf:nodeID="svBMzJkP339"/> + <_3:hasFile rdf:nodeID="svBMzJkP237"/> + <_3:hasFile rdf:nodeID="svBMzJkP407"/> + <_3:hasFile rdf:nodeID="svBMzJkP269"/> + <_3:hasFile rdf:nodeID="svBMzJkP13"/> + <_3:hasFile rdf:nodeID="svBMzJkP307"/> + <_3:hasFile rdf:nodeID="svBMzJkP123"/> + <_3:hasFile rdf:nodeID="svBMzJkP221"/> + <_3:hasFile rdf:nodeID="svBMzJkP345"/> + <_3:hasFile rdf:nodeID="svBMzJkP323"/> + <_3:hasFile rdf:nodeID="svBMzJkP57"/> + <_3:hasFile rdf:nodeID="svBMzJkP193"/> + <_3:hasFile rdf:nodeID="svBMzJkP77"/> + <_3:hasFile rdf:nodeID="svBMzJkP433"/> + <_3:hasFile rdf:nodeID="svBMzJkP39"/> + <_3:hasFile rdf:nodeID="svBMzJkP401"/> + <_3:hasFile rdf:nodeID="svBMzJkP161"/> + <_3:hasFile rdf:nodeID="svBMzJkP283"/> + <_3:hasFile rdf:nodeID="svBMzJkP227"/> + <_3:hasFile rdf:nodeID="svBMzJkP445"/> + <_3:hasFile rdf:nodeID="svBMzJkP425"/> + <_3:hasFile rdf:nodeID="svBMzJkP117"/> + <_3:hasFile rdf:nodeID="svBMzJkP203"/> + <_3:hasFile rdf:nodeID="svBMzJkP403"/> + <_3:hasFile rdf:nodeID="svBMzJkP447"/> + <_3:hasFile rdf:nodeID="svBMzJkP183"/> + <_3:hasFile rdf:nodeID="svBMzJkP87"/> + <_3:hasFile rdf:nodeID="svBMzJkP159"/> + <_3:hasFile rdf:nodeID="svBMzJkP361"/> + <_3:hasFile rdf:nodeID="svBMzJkP145"/> + <_3:hasFile rdf:nodeID="svBMzJkP491"/> + <_3:hasFile rdf:nodeID="svBMzJkP225"/> + <_3:hasFile rdf:nodeID="svBMzJkP61"/> + <_3:hasFile rdf:nodeID="svBMzJkP33"/> + <_3:hasFile rdf:nodeID="svBMzJkP311"/> + <_3:hasFile rdf:nodeID="svBMzJkP239"/> + <_3:hasFile rdf:nodeID="svBMzJkP85"/> + <_3:hasFile rdf:nodeID="svBMzJkP15"/> + <_3:hasFile rdf:nodeID="svBMzJkP81"/> + <_3:hasFile rdf:nodeID="svBMzJkP121"/> + <_3:hasFile rdf:nodeID="svBMzJkP455"/> + <_3:hasFile rdf:nodeID="svBMzJkP359"/> + <_3:hasFile rdf:nodeID="svBMzJkP25"/> + <_3:hasFile rdf:nodeID="svBMzJkP469"/> + <_3:hasFile rdf:nodeID="svBMzJkP477"/> + <_3:hasFile rdf:nodeID="svBMzJkP29"/> + <_3:hasFile rdf:nodeID="svBMzJkP141"/> + <_3:hasFile rdf:nodeID="svBMzJkP285"/> + <_3:hasFile rdf:nodeID="svBMzJkP11"/> + <_3:hasFile rdf:nodeID="svBMzJkP449"/> + <_3:hasFile rdf:nodeID="svBMzJkP435"/> + <_3:hasFile rdf:nodeID="svBMzJkP99"/> + <_3:hasFile rdf:nodeID="svBMzJkP201"/> + <_3:hasFile rdf:nodeID="svBMzJkP181"/> + <_3:hasFile rdf:nodeID="svBMzJkP315"/> + <_3:hasFile rdf:nodeID="svBMzJkP179"/> + <_3:hasFile rdf:nodeID="svBMzJkP399"/> + <_3:hasFile rdf:nodeID="svBMzJkP153"/> + <_3:packageFileName>duktape-1.5.2.tar.xz + <_3:name>Duktape + <_3:homePage rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">http://duktape.org/ + <_3:versionInfo>1.5.2 + <_3:summary>Duktape Ecmascript interpreter + <_3:licenseInfoFromFiles rdf:resource="http://spdx.org/licenses/MIT"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>af6b0cd61c02efa575b9106682606297d26f013b + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ddcaaa8f260ff00f22e09d7fb4b4b7ca94858f30 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>bdb9243b436ef5c70967bddd16d0cc9e74971b1c + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>cb09ad82ed76b6fcaf0ac32db698c1ce50e0a508 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>b3919a740c97b1d3ceb4e03c9ae53456916222a4 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a20231719c1f9b97ea38fbc42dd8af1e21d74879 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>62b2d820f9a27df439cd24ac8766e680d27a95da + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>95a06fb24eca405019eb7b7d535179245eda6099 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ea413ed7d47cf27c6f3ffe25956b1370b653c200 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>0bba41f542f2279b6bfa297ba4e7ee824e3ebd78 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP422"/> + + <_3:fileName>./src-separate/duk_js_ops.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP8"/> + + <_3:fileName>./LICENSE.txt + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>50a3349a079123b6bddf3db507df0dd9e877e246 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP300"/> + + <_3:fileName>./src-separate/duk_bi_logger.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>64566ae0bdc1c3e1017604b6b45d515c30d976eb + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP464"/> + + <_3:fileName>./polyfills/console-minimal.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP224"/> + + <_3:fileName>./src-separate/duk_bi_global.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>2c86a9ed51255ba3b0b225e48c093851a78cae71 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>742635fda10ef9775864077e647b59442768a69c + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP250"/> + + <_3:fileName>./src-separate/duk_api_call.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP398"/> + + <_3:fileName>./src-separate/duk_bi_regexp.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP164"/> + + <_3:fileName>./examples/cmdline/duk_cmdline_ajduk.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP412"/> + + <_3:fileName>./src-separate/duk_heaphdr.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>5ab84f0ff2ed8c4b4a2daa5957d2a20447887103 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>8483a2211d6323480efa605ee646959695b742c6 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>fba891f21dc0b80d282f16d39c37007965adcd04 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>47e1001460004f53dfc350355e02bf56f18b0398 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP114"/> + + <_3:fileName>./examples/eventloop/fileio.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>d529a6faac560def1e5b2cdb991713a6d70b0e26 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>b7be4a3a943099fdf318480615d1c130be87a841 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a9493898a19810a5450d2442d1ff1dfb4ff76d1c + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ee1f62688128fef0954cc9b93e41c199212e5a82 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP66"/> + + <_3:fileName>./debugger/merge_debug_meta.py + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>bc9d119b5e66085e7e4219685fd351fb3f68d800 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP196"/> + + <_3:fileName>./examples/alloc-logging/duk_alloc_logging.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>aa1f72e7a2b4891ec1f445eb031dfba69bdc85de + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>1f430f45a3e52e4327eb17b2213a6f473dc1f6d2 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>9b7de9f9f25d095dfcffbf2d7629cd772fe632f0 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP402"/> + + <_3:fileName>./src-separate/duk_bi_date_windows.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP480"/> + + <_3:fileName>./licenses/murmurhash2.txt + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>88ab1d060886393d94b6fb7c6054a0189117340b + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>d32ab97622eaf870648dfdf8e5b9cb034740affa + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>2e9dca0919a92c68ed30593292b3fe7140480062 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>d5f1184bc60b9049b0dbf1e51ae6a5fe7e5e3192 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>f3ed5c785b60b0f39a74cc3f5b73b0c6e24287c3 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP426"/> + + <_3:fileName>./src-separate/duk_bi_object.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP204"/> + + <_3:fileName>./src-separate/duk_unicode_support.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP160"/> + + <_3:fileName>./examples/hello/hello.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP492"/> + + <_3:fileName>./src/duktape.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP392"/> + + <_3:fileName>./src-separate/duk_bi_duktape.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP34"/> + + <_3:fileName>./Makefile.eventloop + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP312"/> + + <_3:fileName>./src-separate/duk_selftest.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP116"/> + + <_3:fileName>./examples/eventloop/ecma_eventloop.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>01138dd2786346a159c06e43f094d07f002df881 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP406"/> + + <_3:fileName>./src-separate/duk_api_buffer.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP142"/> + + <_3:fileName>./examples/guide/processlines.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>c763ffca7e15df01f44cf89518eb870380b03ee8 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP100"/> + + <_3:fileName>./examples/jxpretty/jxpretty.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>29b1960bc40607c2cf496465068611b2ffc4de87 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>55aa8c67f1fa418f8d625a32a9d6268e9d94429c + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP334"/> + + <_3:fileName>./src-separate/duk_debug_vsnprintf.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP22"/> + + <_3:fileName>./Makefile.coffee + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP212"/> + + <_3:fileName>./src-separate/duk_numconv.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP414"/> + + <_3:fileName>./src-separate/duk_bi_proxy.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> <_3:checksumValue>0783cf4f48c9baf2b3820a36ab276b01e2102600 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP130"/> + + <_3:fileName>./examples/dummy-date-provider/dummy_date_provider.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP140"/> + + <_3:fileName>./examples/guide/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>7edf7600e1a6f09d1e4a0e2f9be418b59fff7c52 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP96"/> + + <_3:fileName>./examples/codepage-conv/duk_codepage_conv.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>61043b4a6f3cf86375ea6e34ebf83b550a1935b2 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>13e6591c152934ace923d9e49cc52872c8a515b9 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP262"/> + + <_3:fileName>./src-separate/duk_hobject_alloc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ca9e1a8f73c5dcbe2e8c45d25ce9865cd93866e6 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>e17ef51b2a16cee731cf341ce08d04690da095ce + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP268"/> + + <_3:fileName>./src-separate/duk_js_call.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>07a167411a356aebfbe987353846a9c711998f20 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP20"/> + + <_3:fileName>./Makefile.cmdline + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP320"/> + + <_3:fileName>./src-separate/duk_hnativefunction.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4fa87de84388dcd955ce27acbe2c2026babf32bc + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>9a31edd2028d39d24aa9bfdbd2b70ce2a64b8493 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP360"/> + + <_3:fileName>./src-separate/duk_hthread_alloc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP176"/> + + <_3:fileName>./examples/debug-trans-socket/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP230"/> + + <_3:fileName>./src-separate/duk_util.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP24"/> + + <_3:fileName>./Makefile.codepage + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>9bcb9de5ed729ecc7093ab48e4f5c04e9704bb30 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP38"/> + + <_3:fileName>./src-noline/metadata.json + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>494667f18c30e4fd36245e6c4e27f93fcf9df87d + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP394"/> + + <_3:fileName>./src-separate/duk_heap_memory.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP296"/> + + <_3:fileName>./src-separate/duk_hobject_class.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>f88d68880f451267e7e2eca4b6c4191e8c3fe011 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP36"/> + + <_3:fileName>./Makefile.jxpretty + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>714e6fe76e2aed0bbb54f6c5e3674472813e4382 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP298"/> + + <_3:fileName>./src-separate/duk_bi_protos.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP172"/> + + <_3:fileName>./examples/debug-trans-socket/duk_trans_socket_unix.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP468"/> + + <_3:fileName>./config/genconfig.py + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>0ec3478b1e5713ffdbe7eb45cd5bb96c1a8a774b + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>7c438de1ba7ca2ef226340d28ec0071ece1c9e43 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4db4ca2d7ce3f076fd195372d53e8bc5714d2597 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a8f8cf615ef79337a83eb791477dc9ed2c22822c + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>d869c0f8797a659124b3ba31c75f494b15bea5e6 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP274"/> + + <_3:fileName>./src-separate/duk_hobject_pc2line.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP390"/> + + <_3:fileName>./src-separate/duk_debugger.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP282"/> + + <_3:fileName>./src-separate/duk_util_bitdecoder.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>5bf6196d028d10a8f2f8e3da67b7d59bb8fd9eff + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP302"/> + + <_3:fileName>./src-separate/duk_unicode_tables.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>29be453689679c9bab977c0b333a4a224d9f02e6 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>d535c4e27319a5db6026553a801e8a5ef0e6fe88 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP216"/> + + <_3:fileName>./src-separate/duk_hobject_misc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>fcdae530da6f6dfafd21219de294c547b91dd866 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>8521b45dcbc72d66c2b4e3f0db9e1dbfb75b45f5 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP84"/> + + <_3:fileName>./examples/alloc-hybrid/duk_alloc_hybrid.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>3b8236810650f4e28bd84984b3c7e55029f241b0 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP454"/> + + <_3:fileName>./polyfills/duktape-error-setter-writable.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>cd7bd1908b56fe13dc63ac64b53ca793221f9359 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP338"/> + + <_3:fileName>./src-separate/duk_heap_markandsweep.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP466"/> + + <_3:fileName>./polyfills/performance-now.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP304"/> + + <_3:fileName>./src-separate/duk_exception.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP188"/> + + <_3:fileName>./examples/sandbox/sandbox.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP110"/> + + <_3:fileName>./examples/eventloop/c_eventloop.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP18"/> + + <_3:fileName>./mandel.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP396"/> + + <_3:fileName>./src-separate/duk_hbufferobject.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>6d5f56a1b76f9dcc9bb68d62ad0df958bd4d38ec + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>10c24a17c2f5f82d8c1a8fab8673c0c9075c1817 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>14ec83aeef66a38c6a4c48a175a544f66d319413 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>2c508fbc7eb127f6793cfe62bf947879668983a4 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>01d4eb01e522172282a4a0ea3aa06f33ce7bec3c + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP94"/> + + <_3:fileName>./examples/codepage-conv/test.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4baffeb2aa785bdc1065eb9ddb8c64c8a028655d + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ed3bd07dbd103d285277ab38c4b4a7dd4a4b654b + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP380"/> + + <_3:fileName>./src-separate/duk_bi_array.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP112"/> + + <_3:fileName>./examples/eventloop/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>9bb6ca1fa3ad4c593b000b2de5aca013b95adda0 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>9406efff4ddfa3fe00ae52c28963df486fc48dfa + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ebbb5b2489ccab8f4a6ef741aac3eafac4c49ebd + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>c2d899e7f2343579f29ad3079fde44eec5d6a544 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP198"/> + + <_3:fileName>./examples/alloc-logging/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>0053a77d6c3562af6d2238f096f3a9bd4b5a834f + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>82ae634976f8641d5582058879d42d843713927b + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>11f16b15a8e52598a078b88a8d0440ff61dd5ba2 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP14"/> + + <_3:fileName>./README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>d650b46e62e2579b3f4c16ee9b5a8abd1c8241b5 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>11ecfff4142b35382d0aaf80ee6c04ae3dfd0b4c + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>0610275779180357a50777f77d1de0e0478f23a7 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>0221b13981af62e7382a806c24f92450597b6106 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4e5a54de08355669dc98b5d4ad379384b33da4e5 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP458"/> + + <_3:fileName>./polyfills/object-assign.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + SPDX license for Duktape 1.5.2 + <_3:referencesFile rdf:nodeID="svBMzJkP127"/> + <_3:referencesFile rdf:nodeID="svBMzJkP101"/> + <_3:referencesFile rdf:nodeID="svBMzJkP21"/> + <_3:referencesFile rdf:nodeID="svBMzJkP337"/> + <_3:referencesFile rdf:nodeID="svBMzJkP55"/> + <_3:referencesFile rdf:nodeID="svBMzJkP91"/> + <_3:referencesFile rdf:nodeID="svBMzJkP413"/> + <_3:referencesFile rdf:nodeID="svBMzJkP321"/> + <_3:referencesFile rdf:nodeID="svBMzJkP129"/> + <_3:referencesFile rdf:nodeID="svBMzJkP139"/> + <_3:referencesFile rdf:nodeID="svBMzJkP473"/> + <_3:referencesFile rdf:nodeID="svBMzJkP357"/> + <_3:referencesFile rdf:nodeID="svBMzJkP419"/> + <_3:referencesFile rdf:nodeID="svBMzJkP451"/> + <_3:referencesFile rdf:nodeID="svBMzJkP95"/> + <_3:referencesFile rdf:nodeID="svBMzJkP115"/> + <_3:referencesFile rdf:nodeID="svBMzJkP79"/> + <_3:referencesFile rdf:nodeID="svBMzJkP275"/> + <_3:referencesFile rdf:nodeID="svBMzJkP191"/> + <_3:referencesFile rdf:nodeID="svBMzJkP261"/> + <_3:referencesFile rdf:nodeID="svBMzJkP23"/> + <_3:referencesFile rdf:nodeID="svBMzJkP353"/> + <_3:referencesFile rdf:nodeID="svBMzJkP267"/> + <_3:referencesFile rdf:nodeID="svBMzJkP427"/> + <_3:referencesFile rdf:nodeID="svBMzJkP119"/> + <_3:referencesFile rdf:nodeID="svBMzJkP205"/> + <_3:referencesFile rdf:nodeID="svBMzJkP335"/> + <_3:referencesFile rdf:nodeID="svBMzJkP211"/> + <_3:referencesFile rdf:nodeID="svBMzJkP19"/> + <_3:referencesFile rdf:nodeID="svBMzJkP149"/> + <_3:referencesFile rdf:nodeID="svBMzJkP319"/> + <_3:referencesFile rdf:nodeID="svBMzJkP367"/> + <_3:referencesFile rdf:nodeID="svBMzJkP265"/> + <_3:referencesFile rdf:nodeID="svBMzJkP441"/> + <_3:referencesFile rdf:nodeID="svBMzJkP385"/> + <_3:referencesFile rdf:nodeID="svBMzJkP289"/> + <_3:referencesFile rdf:nodeID="svBMzJkP175"/> + <_3:referencesFile rdf:nodeID="svBMzJkP277"/> + <_3:referencesFile rdf:nodeID="svBMzJkP125"/> + <_3:referencesFile rdf:nodeID="svBMzJkP471"/> + <_3:referencesFile rdf:nodeID="svBMzJkP229"/> + <_3:referencesFile rdf:nodeID="svBMzJkP143"/> + <_3:referencesFile rdf:nodeID="svBMzJkP415"/> + <_3:referencesFile rdf:nodeID="svBMzJkP137"/> + <_3:referencesFile rdf:nodeID="svBMzJkP219"/> + <_3:referencesFile rdf:nodeID="svBMzJkP37"/> + <_3:referencesFile rdf:nodeID="svBMzJkP429"/> + <_3:referencesFile rdf:nodeID="svBMzJkP485"/> + <_3:referencesFile rdf:nodeID="svBMzJkP63"/> + <_3:referencesFile rdf:nodeID="svBMzJkP295"/> + <_3:referencesFile rdf:nodeID="svBMzJkP301"/> + <_3:referencesFile rdf:nodeID="svBMzJkP231"/> + <_3:referencesFile rdf:nodeID="svBMzJkP89"/> + <_3:referencesFile rdf:nodeID="svBMzJkP35"/> + <_3:referencesFile rdf:nodeID="svBMzJkP349"/> + <_3:referencesFile rdf:nodeID="svBMzJkP297"/> + <_3:referencesFile rdf:nodeID="svBMzJkP271"/> + <_3:referencesFile rdf:nodeID="svBMzJkP171"/> + <_3:referencesFile rdf:nodeID="svBMzJkP467"/> + <_3:referencesFile rdf:nodeID="svBMzJkP393"/> + <_3:referencesFile rdf:nodeID="svBMzJkP417"/> + <_3:referencesFile rdf:nodeID="svBMzJkP331"/> + <_3:referencesFile rdf:nodeID="svBMzJkP291"/> + <_3:referencesFile rdf:nodeID="svBMzJkP185"/> + <_3:referencesFile rdf:nodeID="svBMzJkP327"/> + <_3:referencesFile rdf:nodeID="svBMzJkP313"/> + <_3:referencesFile rdf:nodeID="svBMzJkP147"/> + <_3:referencesFile rdf:nodeID="svBMzJkP363"/> + <_3:referencesFile rdf:nodeID="svBMzJkP97"/> + <_3:referencesFile rdf:nodeID="svBMzJkP49"/> + <_3:referencesFile rdf:nodeID="svBMzJkP409"/> + <_3:referencesFile rdf:nodeID="svBMzJkP41"/> + <_3:referencesFile rdf:nodeID="svBMzJkP243"/> + <_3:referencesFile rdf:nodeID="svBMzJkP151"/> + <_3:referencesFile rdf:nodeID="svBMzJkP439"/> + <_3:referencesFile rdf:nodeID="svBMzJkP213"/> + <_3:referencesFile rdf:nodeID="svBMzJkP379"/> + <_3:referencesFile rdf:nodeID="svBMzJkP131"/> + <_3:referencesFile rdf:nodeID="svBMzJkP333"/> + <_3:referencesFile rdf:nodeID="svBMzJkP47"/> + <_3:referencesFile rdf:nodeID="svBMzJkP369"/> + <_3:referencesFile rdf:nodeID="svBMzJkP209"/> + <_3:referencesFile rdf:nodeID="svBMzJkP273"/> + <_3:referencesFile rdf:nodeID="svBMzJkP31"/> + <_3:referencesFile rdf:nodeID="svBMzJkP73"/> + <_3:referencesFile rdf:nodeID="svBMzJkP293"/> + <_3:referencesFile rdf:nodeID="svBMzJkP389"/> + <_3:referencesFile rdf:nodeID="svBMzJkP27"/> + <_3:referencesFile rdf:nodeID="svBMzJkP281"/> + <_3:referencesFile rdf:nodeID="svBMzJkP259"/> + <_3:referencesFile rdf:nodeID="svBMzJkP75"/> + <_3:referencesFile rdf:nodeID="svBMzJkP443"/> + <_3:referencesFile rdf:nodeID="svBMzJkP287"/> + <_3:referencesFile rdf:nodeID="svBMzJkP383"/> + <_3:referencesFile rdf:nodeID="svBMzJkP317"/> + <_3:referencesFile rdf:nodeID="svBMzJkP69"/> + <_3:referencesFile rdf:nodeID="svBMzJkP155"/> + <_3:referencesFile rdf:nodeID="svBMzJkP157"/> + <_3:referencesFile rdf:nodeID="svBMzJkP279"/> + <_3:referencesFile rdf:nodeID="svBMzJkP215"/> + <_3:referencesFile rdf:nodeID="svBMzJkP217"/> + <_3:referencesFile rdf:nodeID="svBMzJkP71"/> + <_3:referencesFile rdf:nodeID="svBMzJkP83"/> + <_3:referencesFile rdf:nodeID="svBMzJkP199"/> + <_3:referencesFile rdf:nodeID="svBMzJkP53"/> + <_3:referencesFile rdf:nodeID="svBMzJkP105"/> + <_3:referencesFile rdf:nodeID="svBMzJkP341"/> + <_3:referencesFile rdf:nodeID="svBMzJkP195"/> + <_3:referencesFile rdf:nodeID="svBMzJkP347"/> + <_3:referencesFile rdf:nodeID="svBMzJkP253"/> + <_3:referencesFile rdf:nodeID="svBMzJkP133"/> + <_3:referencesFile rdf:nodeID="svBMzJkP305"/> + <_3:referencesFile rdf:nodeID="svBMzJkP169"/> + <_3:referencesFile rdf:nodeID="svBMzJkP465"/> + <_3:referencesFile rdf:nodeID="svBMzJkP303"/> + <_3:referencesFile rdf:nodeID="svBMzJkP187"/> + <_3:referencesFile rdf:nodeID="svBMzJkP489"/> + <_3:referencesFile rdf:nodeID="svBMzJkP351"/> + <_3:referencesFile rdf:nodeID="svBMzJkP109"/> + <_3:referencesFile rdf:nodeID="svBMzJkP103"/> + <_3:referencesFile rdf:nodeID="svBMzJkP9"/> + <_3:referencesFile rdf:nodeID="svBMzJkP17"/> + <_3:referencesFile rdf:nodeID="svBMzJkP395"/> + <_3:referencesFile rdf:nodeID="svBMzJkP381"/> + <_3:referencesFile rdf:nodeID="svBMzJkP431"/> + <_3:referencesFile rdf:nodeID="svBMzJkP343"/> + <_3:referencesFile rdf:nodeID="svBMzJkP481"/> + <_3:referencesFile rdf:nodeID="svBMzJkP251"/> + <_3:referencesFile rdf:nodeID="svBMzJkP421"/> + <_3:referencesFile rdf:nodeID="svBMzJkP189"/> + <_3:referencesFile rdf:nodeID="svBMzJkP405"/> + <_3:referencesFile rdf:nodeID="svBMzJkP299"/> + <_3:referencesFile rdf:nodeID="svBMzJkP487"/> + <_3:referencesFile rdf:nodeID="svBMzJkP93"/> + <_3:referencesFile rdf:nodeID="svBMzJkP463"/> + <_3:referencesFile rdf:nodeID="svBMzJkP67"/> + <_3:referencesFile rdf:nodeID="svBMzJkP423"/> + <_3:referencesFile rdf:nodeID="svBMzJkP329"/> + <_3:referencesFile rdf:nodeID="svBMzJkP107"/> + <_3:referencesFile rdf:nodeID="svBMzJkP165"/> + <_3:referencesFile rdf:nodeID="svBMzJkP111"/> + <_3:referencesFile rdf:nodeID="svBMzJkP355"/> + <_3:referencesFile rdf:nodeID="svBMzJkP223"/> + <_3:referencesFile rdf:nodeID="svBMzJkP483"/> + <_3:referencesFile rdf:nodeID="svBMzJkP387"/> + <_3:referencesFile rdf:nodeID="svBMzJkP255"/> + <_3:referencesFile rdf:nodeID="svBMzJkP453"/> + <_3:referencesFile rdf:nodeID="svBMzJkP391"/> + <_3:referencesFile rdf:nodeID="svBMzJkP7"/> + <_3:referencesFile rdf:nodeID="svBMzJkP249"/> + <_3:referencesFile rdf:nodeID="svBMzJkP241"/> + <_3:referencesFile rdf:nodeID="svBMzJkP197"/> + <_3:referencesFile rdf:nodeID="svBMzJkP263"/> + <_3:referencesFile rdf:nodeID="svBMzJkP177"/> + <_3:referencesFile rdf:nodeID="svBMzJkP397"/> + <_3:referencesFile rdf:nodeID="svBMzJkP245"/> + <_3:referencesFile rdf:nodeID="svBMzJkP113"/> + <_3:referencesFile rdf:nodeID="svBMzJkP475"/> + <_3:referencesFile rdf:nodeID="svBMzJkP59"/> + <_3:referencesFile rdf:nodeID="svBMzJkP247"/> + <_3:referencesFile rdf:nodeID="svBMzJkP375"/> + <_3:referencesFile rdf:nodeID="svBMzJkP437"/> + <_3:referencesFile rdf:nodeID="svBMzJkP173"/> + <_3:referencesFile rdf:nodeID="svBMzJkP163"/> + <_3:referencesFile rdf:nodeID="svBMzJkP411"/> + <_3:referencesFile rdf:nodeID="svBMzJkP373"/> + <_3:referencesFile rdf:nodeID="svBMzJkP371"/> + <_3:referencesFile rdf:nodeID="svBMzJkP65"/> + <_3:referencesFile rdf:nodeID="svBMzJkP459"/> + <_3:referencesFile rdf:nodeID="svBMzJkP461"/> + <_3:referencesFile rdf:nodeID="svBMzJkP257"/> + <_3:referencesFile rdf:nodeID="svBMzJkP325"/> + <_3:referencesFile rdf:nodeID="svBMzJkP43"/> + <_3:referencesFile rdf:nodeID="svBMzJkP45"/> + <_3:referencesFile rdf:nodeID="svBMzJkP51"/> + <_3:referencesFile rdf:nodeID="svBMzJkP457"/> + <_3:referencesFile rdf:nodeID="svBMzJkP365"/> + <_3:referencesFile rdf:nodeID="svBMzJkP167"/> + <_3:referencesFile rdf:nodeID="svBMzJkP479"/> + <_3:referencesFile rdf:nodeID="svBMzJkP233"/> + <_3:referencesFile rdf:nodeID="svBMzJkP135"/> + <_3:referencesFile rdf:nodeID="svBMzJkP377"/> + <_3:referencesFile rdf:nodeID="svBMzJkP309"/> + <_3:referencesFile rdf:nodeID="svBMzJkP235"/> + <_3:referencesFile rdf:nodeID="svBMzJkP207"/> + <_3:referencesFile rdf:nodeID="svBMzJkP339"/> + <_3:referencesFile rdf:nodeID="svBMzJkP237"/> + <_3:referencesFile rdf:nodeID="svBMzJkP407"/> + <_3:referencesFile rdf:nodeID="svBMzJkP269"/> + <_3:referencesFile rdf:nodeID="svBMzJkP13"/> + <_3:referencesFile rdf:nodeID="svBMzJkP307"/> + <_3:referencesFile rdf:nodeID="svBMzJkP123"/> + <_3:referencesFile rdf:nodeID="svBMzJkP221"/> + <_3:referencesFile rdf:nodeID="svBMzJkP345"/> + <_3:referencesFile rdf:nodeID="svBMzJkP323"/> + <_3:referencesFile rdf:nodeID="svBMzJkP57"/> + <_3:referencesFile rdf:nodeID="svBMzJkP193"/> + <_3:referencesFile rdf:nodeID="svBMzJkP77"/> + <_3:referencesFile rdf:nodeID="svBMzJkP433"/> + <_3:referencesFile rdf:nodeID="svBMzJkP39"/> + <_3:referencesFile rdf:nodeID="svBMzJkP401"/> + <_3:referencesFile rdf:nodeID="svBMzJkP161"/> + <_3:referencesFile rdf:nodeID="svBMzJkP283"/> + <_3:referencesFile rdf:nodeID="svBMzJkP227"/> + <_3:referencesFile rdf:nodeID="svBMzJkP445"/> + <_3:referencesFile rdf:nodeID="svBMzJkP425"/> + <_3:referencesFile rdf:nodeID="svBMzJkP117"/> + <_3:referencesFile rdf:nodeID="svBMzJkP203"/> + <_3:referencesFile rdf:nodeID="svBMzJkP403"/> + <_3:referencesFile rdf:nodeID="svBMzJkP447"/> + <_3:referencesFile rdf:nodeID="svBMzJkP183"/> + <_3:referencesFile rdf:nodeID="svBMzJkP87"/> + <_3:referencesFile rdf:nodeID="svBMzJkP159"/> + <_3:referencesFile rdf:nodeID="svBMzJkP361"/> + <_3:referencesFile rdf:nodeID="svBMzJkP145"/> + <_3:referencesFile rdf:nodeID="svBMzJkP491"/> + <_3:referencesFile rdf:nodeID="svBMzJkP225"/> + <_3:referencesFile rdf:nodeID="svBMzJkP61"/> + <_3:referencesFile rdf:nodeID="svBMzJkP33"/> + <_3:referencesFile rdf:nodeID="svBMzJkP311"/> + <_3:referencesFile rdf:nodeID="svBMzJkP239"/> + <_3:referencesFile rdf:nodeID="svBMzJkP85"/> + <_3:referencesFile rdf:nodeID="svBMzJkP15"/> + <_3:referencesFile rdf:nodeID="svBMzJkP81"/> + <_3:referencesFile rdf:nodeID="svBMzJkP121"/> + <_3:referencesFile rdf:nodeID="svBMzJkP455"/> + <_3:referencesFile rdf:nodeID="svBMzJkP359"/> + <_3:referencesFile rdf:nodeID="svBMzJkP25"/> + <_3:referencesFile rdf:nodeID="svBMzJkP469"/> + <_3:referencesFile rdf:nodeID="svBMzJkP477"/> + <_3:referencesFile rdf:nodeID="svBMzJkP29"/> + <_3:referencesFile rdf:nodeID="svBMzJkP141"/> + <_3:referencesFile rdf:nodeID="svBMzJkP285"/> + <_3:referencesFile rdf:nodeID="svBMzJkP11"/> + <_3:referencesFile rdf:nodeID="svBMzJkP449"/> + <_3:referencesFile rdf:nodeID="svBMzJkP435"/> + <_3:referencesFile rdf:nodeID="svBMzJkP99"/> + <_3:referencesFile rdf:nodeID="svBMzJkP201"/> + <_3:referencesFile rdf:nodeID="svBMzJkP181"/> + <_3:referencesFile rdf:nodeID="svBMzJkP315"/> + <_3:referencesFile rdf:nodeID="svBMzJkP179"/> + <_3:referencesFile rdf:nodeID="svBMzJkP399"/> + <_3:referencesFile rdf:nodeID="svBMzJkP153"/> + + <_3:dataLicense rdf:resource="http://spdx.org/licenses/CC0-1.0"/> + <_3:creationInfo rdf:nodeID="svBMzJkP3"/> + <_3:describesPackage rdf:nodeID="svBMzJkP4"/> + <_3:specVersion>SPDX-1.2 + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP382"/> + + <_3:fileName>./src-separate/duk_api_codec.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP234"/> + + <_3:fileName>./src-separate/duk_hthread_misc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP236"/> + + <_3:fileName>./src-separate/duk_js.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP208"/> + + <_3:fileName>./src-separate/duk_regexp_executor.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>d49c1cdb51b3a4fdd823c13831617a1f0a93edd1 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ef83823d07ee05f2373502187af9700d5c2aa952 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP238"/> + + <_3:fileName>./src-separate/duk_js_compiler.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>982e40839854be361e3b57b5c07ef4f710ab749b + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP308"/> + + <_3:fileName>./src-separate/duk_replacements.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP124"/> + + <_3:fileName>./examples/eventloop/client-socket-test.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP310"/> + + <_3:fileName>./src-separate/duk_util_hashprime.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP348"/> + + <_3:fileName>./src-separate/duk_json.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP150"/> + + <_3:fileName>./examples/guide/primecheck.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP186"/> + + <_3:fileName>./examples/debug-trans-dvalue/test.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>f788091973ac91ad9562aaadac9c2de87af2ba76 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>e70f9a590f4288c0feee56aa2c421cbc23036a1e + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>75c61dd080cd643b7449f673105b7b7e4bdda0f5 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>215f6fec820889330048f7f2c1b5a220eb963657 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP448"/> + + <_3:fileName>./src-separate/duk_bi_pointer.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP88"/> + + <_3:fileName>./examples/alloc-hybrid/duk_alloc_hybrid.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>2321e0a68bf940f8346d00adda9e4a58fa51f608 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP226"/> + + <_3:fileName>./src-separate/duk_bi_function.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP16"/> + + <_3:fileName>./Makefile.hello + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP82"/> + + <_3:fileName>./examples/coffee/globals.coffee + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>949e147e9b5e284590449d0e8f74427c8c12f00f + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP456"/> + + <_3:fileName>./polyfills/object-prototype-definegetter.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP26"/> + + <_3:fileName>./Makefile.sandbox + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP478"/> + + <_3:fileName>./extras/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP462"/> + + <_3:fileName>./polyfills/duktape-isfastint.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP286"/> + + <_3:fileName>./src-separate/duk_api_logging.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP12"/> + + <_3:fileName>./Makefile.sharedlibrary + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>0f87aa4dae2a89f7ed3163197f96790ec6b28b19 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>e44b8b092afcfa97e693eb3e0be97d41f8aff301 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP316"/> + + <_3:fileName>./src-separate/duk_api_heap.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP180"/> + + <_3:fileName>./examples/debug-trans-dvalue/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>8c5ee5b508a23ac5089a7e6c76593b6678965869 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>7f45dbd1e665b257c7186982b8b3362753856b18 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP56"/> + + <_3:fileName>./debugger/duk_debugcommands.yaml + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP92"/> + + <_3:fileName>./examples/codepage-conv/duk_codepage_conv.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>62ecbef7a21dd5c49b38fbe344e2511c07f36261 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>030ac3c728cca19fe93d652a4b6b8758d739d9b9 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>09ee87b3ae8afe8b7c2295127835b05b00603b25 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP474"/> + + <_3:fileName>./config/duk_config.h-modular-static + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4fae13370046b51fe87c60fa86eb14f2948fd143 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>c06e1c0dcc0c61e40f7337b40917df034f167e54 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>dfd71ae51277aae2fe511f4df732a20bc72ab75a + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP420"/> + + <_3:fileName>./src-separate/duk_bi_thread.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>641b29e08addaa543f37561f5a35689f5fba876e + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>fb9c2ff459fd84b4587f846fbd36219cf8f06931 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>b1c899faac8f0a8b1f7844d8c773ce5e6d9262d1 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP192"/> + + <_3:fileName>./examples/alloc-logging/duk_alloc_logging.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>d45e3fc443887261ce432a807aaebd2a1812264e + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP428"/> + + <_3:fileName>./src-separate/duk_api_var.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP120"/> + + <_3:fileName>./examples/eventloop/basic-test.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP206"/> + + <_3:fileName>./src-separate/duk_builtins.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>c8ae046bda2c920b5d807dfa68c8159b655b0873 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>f20291ecae9e775ebac2a6ed24f5399c2b3a7883 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP386"/> + + <_3:fileName>./src-separate/duk_heap_alloc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>239011a773fbafa409c2f02b5e889bd5d28d16e1 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>6a1500fea27ea278c4f0c64d908e16cc60df684b + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP472"/> + + <_3:fileName>./config/duk_config.h-modular-dll + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>c33541d338ff3d8461dd1a8573a6372e19cb12e4 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP232"/> + + <_3:fileName>./src-separate/duk_hstring_misc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP90"/> + + <_3:fileName>./examples/codepage-conv/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>f396c6aec456b183ef77e33da1dfffc89c417056 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a9db75839022e7dcf7e691ada7480a9b7c2715d0 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a2c79a55a60f73e1a1567b96d584399571180ef5 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>92ce3decf72b10b0023116ac727a752e8749aa90 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>339f26c72e051cf531426a63fe6c35c476bad645 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a9206a7b46f8d8319b798475650217f494fa76ab + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>fa85ee3394206d18c611b837e700257ba8336250 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP292"/> + + <_3:fileName>./src-separate/duk_bi_json.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>149fd21526c90d52b22e77b297f76e6da3e656ff + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>03cad085177f1e776be90afceef1f2160e6c8bf4 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP50"/> + + <_3:fileName>./debugger/duk_debug_proxy.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP410"/> + + <_3:fileName>./src-separate/duk_debugger.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP42"/> + + <_3:fileName>./src-noline/duktape.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP244"/> + + <_3:fileName>./src-separate/duk_strings.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP152"/> + + <_3:fileName>./examples/guide/prime.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP132"/> + + <_3:fileName>./examples/eval/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>62a4483b185b620431e13ddb2b18555baa344937 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a476b63d336a8d171891330c965fbb8b72f5863a + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP28"/> + + <_3:fileName>./AUTHORS.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP260"/> + + <_3:fileName>./src-separate/duk_regexp.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP288"/> + + <_3:fileName>./src-separate/duk_bi_math.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>a32730ebb239feb5599bcac3561b7a0acb3a1b94 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP318"/> + + <_3:fileName>./src-separate/duk_hthread_stacks.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>87018db6c5898305a7e5196d9590c5b42424a7ea + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>2df8e3d302a5c74ac385b0e1e110d0845a4aef35 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>5ab84f0ff2ed8c4b4a2daa5957d2a20447887103 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>484fb41d516abcbe8c97af5aa80b76c67dbfb0cb + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP490"/> + + <_3:fileName>./src/duktape.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP200"/> + + <_3:fileName>./src-separate/duk_bi_error.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP60"/> + + <_3:fileName>./debugger/package.json + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP10"/> + + <_3:fileName>./duk_build_meta.json + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP432"/> + + <_3:fileName>./src-separate/duk_util_hashbytes.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>206ffd13c06208e85baba2b257fe3ddebb56a6c2 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>6b438afc07b9ac67fb6ea8bc9d4f01f3b362c9e1 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>73ff75213f392b6125c68ab6b430176dfad71269 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP452"/> + + <_3:fileName>./polyfills/duktape-error-setter-nonwritable.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>24a2346fa389c2294cc0e96427e0bd206dac10b9 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ff17cbc9cb84b86f83bb104a247e5c265a9fe5b5 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>5ab84f0ff2ed8c4b4a2daa5957d2a20447887103 + + + + <_3:packageVerificationCodeExcludedFile>./license.spdx + <_3:packageVerificationCodeValue>a60d2f27825f0294858de60a5ef8f35433967a27 + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP68"/> + + <_3:fileName>./debugger/static/style.css + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP330"/> + + <_3:fileName>./src-separate/duk_hcompiledfunction.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP242"/> + + <_3:fileName>./src-separate/duk_util_misc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>036a814b2c1187af4c5c882095bd6b3d710cb79a + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>6fdfe8f7b5fc3226d83f0246079f76b33d4bcb9b + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>b381ea15009eb8140c0789203345cdcc2c6c1cd6 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>6c4bfae55df6a1fef08fd758e32bf465316cab9a + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>734560a1ac6155f124000b5a93569aae99149b6c + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP266"/> + + <_3:fileName>./src-separate/duk_bi_string.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>64edd8d85b88c69b5c2c686b85f19b350bef7880 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>1c40a52fd54baf7ac334fce4829892d5d951401a + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP252"/> + + <_3:fileName>./src-separate/duk_lexer.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP430"/> + + <_3:fileName>./src-separate/duk_api_stack.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>fbe432d33d4ef75f30fa2d87f4f1a83f78b4811b + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP178"/> + + <_3:fileName>./examples/debug-trans-dvalue/duk_trans_dvalue.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>bc9d119b5e66085e7e4219685fd351fb3f68d800 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP246"/> + + <_3:fileName>./src-separate/duk_unicode.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>3da07a99a4ed68844140352133867b2857fab685 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP476"/> + + <_3:fileName>./config/genconfig_metadata.tar.gz + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP344"/> + + <_3:fileName>./src-separate/duk_api_memory.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP378"/> + + <_3:fileName>./src-separate/duk_hobject.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4392fa63e6e9174ec09ef2e3a4e4e3bd03e94126 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>9b95f60e95f7da3773bdac1d2a436b3c5a662ab1 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>6985052d270ff2a00543b641115b946fc91ebf3a + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>f9072f5c361c86887b57ce662b3cd7211b4ce346 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>5d593ae6316ed7a3ea6e7ed0a47267745d79d12d + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ddbc206357dd4b97f3630b87bfdac148a5e8b190 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP258"/> + + <_3:fileName>./src-separate/duk_hbuffer_alloc.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP44"/> + + <_3:fileName>./src-noline/duktape.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP52"/> + + <_3:fileName>./debugger/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP74"/> + + <_3:fileName>./examples/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>89a7d62e8ae337fca35cacbb4b4cc6f294daedc9 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>5f89525f75f61dd8c89e010cb62bc071d6d13170 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>4396fb38f8a42bfc90ef1bc7c11c402074367343 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ab29fe562681a0e6785515ef284fc51a20f0f7b5 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>ebaa68746ec59e01ef742f68aab11e053f882f63 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP388"/> + + <_3:fileName>./src-separate/duk_util_bitencoder.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>8ddbeb97a1a5acc3bed35f4df60e3aa1f4267380 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP98"/> + + <_3:fileName>./examples/jxpretty/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP168"/> + + <_3:fileName>./examples/cmdline/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP222"/> + + <_3:fileName>./src-separate/duk_error.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP194"/> + + <_3:fileName>./examples/alloc-logging/log2gnuplot.py + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP78"/> + + <_3:fileName>./examples/coffee/hello.coffee + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>0125ebcabe62cef4923e75527d3128e8c48cdf1f + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP438"/> + + <_3:fileName>./src-separate/duk_bi_number.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>c1685717742f3e9af9c901796a8bb5a08950461f + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>e172079513ed0c12550285bcbc4d6bfc83985676 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP174"/> + + <_3:fileName>./examples/debug-trans-socket/duk_trans_socket.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>52b4480b68f7f8bf93543d3bb795cdc5ade66fba + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>93573df8348a41adb790f59e39bf99d9a7bf3a3d + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP146"/> + + <_3:fileName>./examples/guide/fib.js + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>127e52c8b193d777811c25ceaab2c97c26a2bdab + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>601a6783177c1c6140c12b42c0bedb0ee0079d16 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>02741b89fd8d8df210223a3da3a200d0f609d803 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP240"/> + + <_3:fileName>./src-separate/duk_hobject_finalizer.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>44c9219558aba26dc69982a9f432028290707c36 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP86"/> + + <_3:fileName>./examples/alloc-hybrid/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>1289ac12dfcacbe472caea1333de3fbe70a5662c + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>3d700df1f765c39fc63bfd4e31a9d7da8d15c543 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP122"/> + + <_3:fileName>./examples/eventloop/poll.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>e5a5f0db067ec56c6d2f7356f412222a8884dc92 + + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>46f70bf98738ea7c9e5b353490d3e8815c610aa6 + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP202"/> + + <_3:fileName>./src-separate/duk_error_throw.c + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP182"/> + + <_3:fileName>./examples/debug-trans-dvalue/Makefile + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP362"/> + + <_3:fileName>./src-separate/duk_config.h + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> + <_3:checksumValue>58c701ade28ee5a475dede84a6e771893e3fc40f + + + + <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> + <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> + <_3:copyrightText>Copyright 2013-2016 Duktape authors (see AUTHORS.rst in the Duktape distributable) + <_3:checksum rdf:nodeID="svBMzJkP154"/> + + <_3:fileName>./examples/alloc-torture/README.rst + <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/licenses/commonjs.txt b/ceph/src/civetweb/src/third_party/duktape-1.5.2/licenses/commonjs.txt similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/licenses/commonjs.txt rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/licenses/commonjs.txt diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/licenses/lua.txt b/ceph/src/civetweb/src/third_party/duktape-1.5.2/licenses/lua.txt new file mode 100644 index 000000000..24e65f1cf --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/licenses/lua.txt @@ -0,0 +1 @@ +Lua is under the MIT license: http://www.lua.org/license.html. diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/licenses/murmurhash2.txt b/ceph/src/civetweb/src/third_party/duktape-1.5.2/licenses/murmurhash2.txt similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/licenses/murmurhash2.txt rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/licenses/murmurhash2.txt diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/mandel.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/mandel.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/mandel.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/mandel.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/console-minimal.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/console-minimal.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/console-minimal.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/console-minimal.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/duktape-error-setter-nonwritable.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/duktape-error-setter-nonwritable.js new file mode 100644 index 000000000..236c706b2 --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/duktape-error-setter-nonwritable.js @@ -0,0 +1,20 @@ +/* + * Ensure Error .fileName, .lineNumber, and .stack are not directly writable, + * but can be written using Object.defineProperty(). This matches Duktape + * 1.3.0 and prior. + * + * See: https://github.com/svaarala/duktape/pull/390. + */ + +(function () { + var err = new Error('test'); + err.fileName = 999; + if (err.fileName !== 999) { return; } // already non-writable + + var fn = new Function(''); // nop + Object.defineProperties(Error.prototype, { + fileName: { set: fn }, + lineNumber: { set: fn }, + stack: { set: fn } + }); +})(); diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/duktape-error-setter-writable.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/duktape-error-setter-writable.js new file mode 100644 index 000000000..5d487cdfe --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/duktape-error-setter-writable.js @@ -0,0 +1,19 @@ +/* + * Ensure Error .fileName, .lineNumber, and .stack are directly writable + * without having to use Object.defineProperty(). This matches Duktape + * 1.4.0 behavior. + * + * See: https://github.com/svaarala/duktape/pull/390. + */ + +(function () { + var err = new Error('test'); + err.fileName = 999; + if (err.fileName === 999) { return; } // already writable + + Object.defineProperties(Error.prototype, { + fileName: { set: new Function('v', 'Object.defineProperty(this, "fileName", { value: v, writable: true, enumerable: false, configurable: true });') }, + lineNumber: { set: new Function('v', 'Object.defineProperty(this, "lineNumber", { value: v, writable: true, enumerable: false, configurable: true });') }, + stack: { set: new Function('v', 'Object.defineProperty(this, "stack", { value: v, writable: true, enumerable: false, configurable: true });') }, + }); +})(); diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/duktape-isfastint.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/duktape-isfastint.js similarity index 95% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/duktape-isfastint.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/duktape-isfastint.js index dce2d9edb..68219e42b 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/duktape-isfastint.js +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/duktape-isfastint.js @@ -16,7 +16,7 @@ if (typeof Duktape === 'object') { if (typeof Duktape.fastintTag === 'undefined') { Object.defineProperty(Duktape, 'fastintTag', { /* Tag number depends on duk_tval packing. */ - value: (Duktape.info(true)[1] === 0xfff4) ? + value: (Duktape.info(true)[1] >= 0xfff0) ? 0xfff1 /* tag for packed duk_tval */ : 1 /* tag for unpacked duk_tval */, writable: false, diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/object-assign.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/object-assign.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/object-assign.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/object-assign.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/object-prototype-definegetter.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/object-prototype-definegetter.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/object-prototype-definegetter.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/object-prototype-definegetter.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/object-prototype-definesetter.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/object-prototype-definesetter.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/object-prototype-definesetter.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/object-prototype-definesetter.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/performance-now.js b/ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/performance-now.js similarity index 100% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/polyfills/performance-now.js rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/polyfills/performance-now.js diff --git a/ceph/src/civetweb/src/third_party/duktape-1.3.0/src-separate/duk_config.h b/ceph/src/civetweb/src/third_party/duktape-1.5.2/src-noline/duk_config.h similarity index 56% rename from ceph/src/civetweb/src/third_party/duktape-1.3.0/src-separate/duk_config.h rename to ceph/src/civetweb/src/third_party/duktape-1.5.2/src-noline/duk_config.h index 5ce86e1bc..ef622353f 100644 --- a/ceph/src/civetweb/src/third_party/duktape-1.3.0/src-separate/duk_config.h +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/src-noline/duk_config.h @@ -1,155 +1,269 @@ /* - * Determine platform features, select feature selection defines - * (e.g. _XOPEN_SOURCE), include system headers, and define DUK_USE_xxx - * defines which are (only) checked in Duktape internal code for - * activated features. Duktape feature selection is based on automatic - * feature detection, user supplied DUK_OPT_xxx defines, and optionally - * a "duk_custom.h" user header (if DUK_OPT_HAVE_CUSTOM_H is defined). + * duk_config.h configuration header generated by genconfig.py. * - * When compiling Duktape, DUK_COMPILING_DUKTAPE is set, and this file - * is included before any system headers are included. Feature selection - * defines (e.g. _XOPEN_SOURCE) are defined here before any system headers - * are included (which is a requirement for system headers to work correctly). - * This file is responsible for including all system headers and contains - * all platform dependent cruft in general. When compiling user code, - * DUK_COMPILING_DUKTAPE is not defined, and we must avoid e.g. defining - * unnecessary feature selection defines. + * Git commit: cad34ae155acb0846545ca6bf2d29f9463b22bbb + * Git describe: v1.5.2 + * Git branch: HEAD * - * The general order of handling: - * - Compiler feature detection (require no includes) - * - Intermediate platform detection (-> easier platform defines) - * - Platform detection, system includes, byte order detection, etc - * - ANSI C wrappers (e.g. DUK_MEMCMP), wrappers for constants, etc - * - DUK_USE_xxx defines are resolved based on input defines - * - Duktape Date provider settings - * - Final sanity checks + * Supported platforms: + * - Mac OSX, iPhone, Darwin + * - OpenBSD + * - Generic BSD + * - Atari ST TOS + * - AmigaOS + * - Windows + * - Flashplayer (Crossbridge) + * - QNX + * - TI-Nspire + * - Emscripten + * - Linux + * - Solaris + * - Generic POSIX + * - Cygwin + * - Generic UNIX + * - Generic fallback * - * DUK_F_xxx are internal feature detection macros which should not be - * used outside this header. + * Supported architectures: + * - x86 + * - x64 + * - x32 + * - ARM 32-bit + * - ARM 64-bit + * - MIPS 32-bit + * - MIPS 64-bit + * - PowerPC 32-bit + * - PowerPC 64-bit + * - SPARC 32-bit + * - SPARC 64-bit + * - SuperH + * - Motorola 68k + * - Emscripten + * - Generic * - * Useful resources: + * Supported compilers: + * - Clang + * - GCC + * - MSVC + * - Emscripten + * - TinyC + * - VBCC + * - Bruce's C compiler + * - Generic * - * http://sourceforge.net/p/predef/wiki/Home/ - * http://sourceforge.net/p/predef/wiki/Architectures/ - * http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor - * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types - * - * Preprocessor defines available in a particular GCC: - * - * gcc -dM -E - = 199901L) -#define DUK_F_C99 +/* DLL build detection */ +#if defined(DUK_OPT_DLL_BUILD) +#define DUK_F_DLL_BUILD +#elif defined(DUK_OPT_NO_DLL_BUILD) +#undef DUK_F_DLL_BUILD +#else +/* not configured for DLL build */ +#undef DUK_F_DLL_BUILD #endif +/* Apple OSX, iOS */ +#if defined(__APPLE__) +#define DUK_F_APPLE +#endif + +/* OpenBSD */ +#if defined(__OpenBSD__) || defined(__OpenBSD) +#define DUK_F_OPENBSD +#endif + +/* NetBSD */ +#if defined(__NetBSD__) || defined(__NetBSD) +#define DUK_F_NETBSD +#endif + +/* FreeBSD */ +#if defined(__FreeBSD__) || defined(__FreeBSD) +#define DUK_F_FREEBSD +#endif + +/* BSD variant */ +#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ + defined(__bsdi__) || defined(__DragonFly__) +#define DUK_F_BSD +#endif + +/* Atari ST TOS. __TOS__ defined by PureC. No platform define in VBCC + * apparently, so to use with VBCC user must define __TOS__ manually. + */ +#if defined(__TOS__) +#define DUK_F_TOS +#endif + +/* Motorola 68K. Not defined by VBCC, so user must define one of these + * manually when using VBCC. + */ +#if defined(__m68k__) || defined(M68000) || defined(__MC68K__) +#define DUK_F_M68K +#endif + +/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must + * define 'AMIGA' manually when using VBCC. + */ +#if defined(AMIGA) || defined(__amigaos__) +#define DUK_F_AMIGAOS +#endif + +/* PowerPC */ +#if defined(__powerpc) || defined(__powerpc__) || defined(__PPC__) +#define DUK_F_PPC +#if defined(__PPC64__) || defined(__LP64__) || defined(_LP64) +#define DUK_F_PPC64 +#else +#define DUK_F_PPC32 +#endif +#endif + +/* Windows, both 32-bit and 64-bit */ +#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ + defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) +#define DUK_F_WINDOWS +#if defined(_WIN64) || defined(WIN64) +#define DUK_F_WIN64 +#else +#define DUK_F_WIN32 +#endif +#endif + +/* Flash player (e.g. Crossbridge) */ +#if defined(__FLASHPLAYER__) +#define DUK_F_FLASHPLAYER +#endif + +/* QNX */ +#if defined(__QNX__) +#define DUK_F_QNX +#endif + +/* TI-Nspire (using Ndless) */ +#if defined(_TINSPIRE) +#define DUK_F_TINSPIRE +#endif + +/* Emscripten (provided explicitly by user), improve if possible */ +#if defined(EMSCRIPTEN) +#define DUK_F_EMSCRIPTEN +#endif + +/* BCC (Bruce's C compiler): this is a "torture target" for compilation */ +#if defined(__BCC__) || defined(__BCC_VERSION__) +#define DUK_F_BCC +#endif + +/* Linux */ +#if defined(__linux) || defined(__linux__) || defined(linux) +#define DUK_F_LINUX +#endif + +/* illumos / Solaris */ +#if defined(__sun) && defined(__SVR4) +#define DUK_F_SUN +#endif + +/* POSIX */ +#if defined(__posix) +#define DUK_F_POSIX +#endif + +/* Cygwin */ +#if defined(__CYGWIN__) +#define DUK_F_CYGWIN +#endif + +/* Generic Unix (includes Cygwin) */ +#if defined(__unix) || defined(__unix__) || defined(unix) || \ + defined(DUK_F_LINUX) || defined(DUK_F_BSD) +#define DUK_F_UNIX +#endif + +/* stdint.h not available */ +#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) +#if (_MSC_VER < 1700) +/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ +#define DUK_F_NO_STDINT_H +#endif +#endif +#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC)) +#define DUK_F_NO_STDINT_H +#endif + +/* C++ */ #undef DUK_F_CPP #if defined(__cplusplus) #define DUK_F_CPP #endif -#undef DUK_F_CPP11 -#if defined(__cplusplus) && (__cplusplus >= 201103L) -#define DUK_F_CPP11 -#endif - -/* - * Provides the duk_rdtsc() inline function (if available), limited to - * GCC C99. - * - * See: http://www.mcs.anl.gov/~kazutomo/rdtsc.html +/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), + * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. + * https://sites.google.com/site/x32abi/ */ - -/* XXX: more accurate detection of what gcc versions work; more inline - * asm versions for other compilers. - */ -#if defined(__GNUC__) && defined(__i386__) && defined(DUK_F_C99) && \ - !defined(__cplusplus) /* unsigned long long not standard */ -static __inline__ unsigned long long duk_rdtsc(void) { - unsigned long long int x; - __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); - return x; -} -#define DUK_USE_RDTSC() duk_rdtsc() -#elif defined(__GNUC__) && defined(__x86_64__) && defined(DUK_F_C99) && \ - !defined(__cplusplus) /* unsigned long long not standard */ -static __inline__ unsigned long long duk_rdtsc(void) { - unsigned hi, lo; - __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); - return ((unsigned long long) lo) | (((unsigned long long) hi) << 32); -} -#define DUK_USE_RDTSC() duk_rdtsc() -#else -/* not available */ -#undef DUK_USE_RDTSC -#endif - -/* - * Intermediate platform, architecture, and compiler detection. These are - * hopelessly intertwined - e.g. architecture defines depend on compiler etc. - * - * Provide easier defines for platforms and compilers which are often tricky - * or verbose to detect. The intent is not to provide intermediate defines for - * all features; only if existing feature defines are inconvenient. - */ - -/* Intel x86 (32-bit) */ -#if defined(i386) || defined(__i386) || defined(__i386__) || \ - defined(__i486__) || defined(__i586__) || defined(__i686__) || \ - defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \ - defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) -#define DUK_F_X86 -#endif - -/* AMD64 (64-bit) */ #if defined(__amd64__) || defined(__amd64) || \ defined(__x86_64__) || defined(__x86_64) || \ defined(_M_X64) || defined(_M_AMD64) +#if defined(__ILP32__) || defined(_ILP32) +#define DUK_F_X32 +#else #define DUK_F_X64 #endif - -/* X32: 64-bit with 32-bit pointers (allows packed tvals). X32 support is - * not very mature yet. - * - * https://sites.google.com/site/x32abi/ - */ -#if defined(DUK_F_X64) && \ - (defined(_ILP32) || defined(__ILP32__)) -#define DUK_F_X32 -/* define only one of: DUK_F_X86, DUK_F_X32, or DUK_F_X64 */ -#undef DUK_F_X64 -#undef DUK_F_X86 +#elif defined(i386) || defined(__i386) || defined(__i386__) || \ + defined(__i486__) || defined(__i586__) || defined(__i686__) || \ + defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \ + defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) +#if defined(__LP64__) || defined(_LP64) +/* This should not really happen, but would indicate x64. */ +#define DUK_F_X64 +#else +#define DUK_F_X86 +#endif #endif /* ARM */ #if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) #define DUK_F_ARM +#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) +#define DUK_F_ARM64 +#else +#define DUK_F_ARM32 +#endif #endif -/* MIPS */ -/* Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */ +/* MIPS. Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */ #if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \ defined(_R3000) || defined(_R4000) || defined(_R5900) || \ defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \ defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \ defined(__mips) || defined(__MIPS__) #define DUK_F_MIPS -#if defined(__LP64__) || defined(__mips64) || defined(__mips64__) || \ - defined(__mips_n64) +#if defined(__LP64__) || defined(_LP64) || defined(__mips64) || \ + defined(__mips64__) || defined(__mips_n64) #define DUK_F_MIPS64 #else #define DUK_F_MIPS32 #endif #endif +/* SPARC */ +#if defined(sparc) || defined(__sparc) || defined(__sparc__) +#define DUK_F_SPARC +#if defined(__LP64__) || defined(_LP64) +#define DUK_F_SPARC64 +#else +#define DUK_F_SPARC32 +#endif +#endif + /* SuperH */ #if defined(__sh__) || \ defined(__sh1__) || defined(__SH1__) || \ @@ -160,107 +274,25 @@ static __inline__ unsigned long long duk_rdtsc(void) { #define DUK_F_SUPERH #endif -/* Motorola 68K. Not defined by VBCC, so user must define one of these - * manually when using VBCC. - */ -#if defined(__m68k__) || defined(M68000) || defined(__MC68K__) -#define DUK_F_M68K +/* Clang */ +#if defined(__clang__) +#define DUK_F_CLANG #endif -/* PowerPC */ -#if defined(__powerpc) || defined(__powerpc__) || defined(__PPC__) -#define DUK_F_PPC -#if defined(__PPC64__) -#define DUK_F_PPC64 -#else -#define DUK_F_PPC32 -#endif +/* C99 or above */ +#undef DUK_F_C99 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define DUK_F_C99 #endif -/* Linux */ -#if defined(__linux) || defined(__linux__) || defined(linux) -#define DUK_F_LINUX +/* C++11 or above */ +#undef DUK_F_CPP11 +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define DUK_F_CPP11 #endif -/* FreeBSD */ -#if defined(__FreeBSD__) || defined(__FreeBSD) -#define DUK_F_FREEBSD -#endif - -/* NetBSD */ -#if defined(__NetBSD__) || defined(__NetBSD) -#define DUK_F_NETBSD -#endif - -/* OpenBSD */ -#if defined(__OpenBSD__) || defined(__OpenBSD) -#define DUK_F_OPENBSD -#endif - -/* BSD variant */ -#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ - defined(__bsdi__) || defined(__DragonFly__) -#define DUK_F_BSD -#endif - -/* Generic Unix (includes Cygwin) */ -#if defined(__unix) || defined(__unix__) || defined(unix) || \ - defined(DUK_F_LINUX) || defined(DUK_F_BSD) -#define DUK_F_UNIX -#endif - -/* Cygwin */ -#if defined(__CYGWIN__) -#define DUK_F_CYGWIN -#endif - -/* Windows (32-bit or above) */ -#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ - defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) -#define DUK_F_WINDOWS -#endif - -#if defined(__APPLE__) -#define DUK_F_APPLE -#endif - -/* Atari ST TOS. __TOS__ defined by PureC (which doesn't work as a target now - * because int is 16-bit, to be fixed). No platform define in VBCC apparently, - * so to use with VBCC, user must define '__TOS__' manually. - */ -#if defined(__TOS__) -#define DUK_F_TOS -#endif - -/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must - * define 'AMIGA' manually. - */ -#if defined(AMIGA) || defined(__amigaos__) -#define DUK_F_AMIGAOS -#endif - -/* Flash player (e.g. Crossbridge) */ -#if defined(__FLASHPLAYER__) -#define DUK_F_FLASHPLAYER -#endif - -/* Emscripten (provided explicitly by user), improve if possible */ -#if defined(EMSCRIPTEN) -#define DUK_F_EMSCRIPTEN -#endif - -/* QNX */ -#if defined(__QNX__) -#define DUK_F_QNX -#endif - -/* TI-Nspire (using Ndless) */ -#if defined(_TINSPIRE) -#define DUK_F_TINSPIRE -#endif - -/* GCC and GCC version convenience define. */ -#if defined(__GNUC__) +/* GCC. Clang also defines __GNUC__ so don't detect GCC if using Clang. */ +#if defined(__GNUC__) && !defined(__clang__) && !defined(DUK_F_CLANG) #define DUK_F_GCC #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) /* Convenience, e.g. gcc 4.5.1 == 40501; http://stackoverflow.com/questions/6031819/emulating-gccs-builtin-unreachable */ @@ -270,16 +302,9 @@ static __inline__ unsigned long long duk_rdtsc(void) { #endif #endif -/* Clang */ -#if defined(__clang__) -#define DUK_F_CLANG -/* It seems clang also defines __GNUC__, so undo the GCC detection. */ -#if defined(DUK_F_GCC) -#undef DUK_F_GCC -#endif -#if defined(DUK_F_GCC_VERSION) -#undef DUK_F_GCC_VERSION -#endif +/* MinGW. Also GCC flags (DUK_F_GCC) are enabled now. */ +#if defined(__MINGW32__) || defined(__MINGW64__) +#define DUK_F_MINGW #endif /* MSVC */ @@ -298,106 +323,26 @@ static __inline__ unsigned long long duk_rdtsc(void) { #endif #endif /* _MSC_VER */ -/* MinGW */ -#if defined(__MINGW32__) || defined(__MINGW64__) -/* NOTE: Also GCC flags are detected (DUK_F_GCC etc). */ -#define DUK_F_MINGW -#endif - -/* BCC (Bruce's C compiler): this is a "torture target" for compilation */ -#if defined(__BCC__) || defined(__BCC_VERSION__) -#define DUK_F_BCC +/* TinyC */ +#if defined(__TINYC__) +/* http://bellard.org/tcc/tcc-doc.html#SEC9 */ +#define DUK_F_TINYC #endif +/* VBCC */ #if defined(__VBCC__) #define DUK_F_VBCC #endif +/* Atari Mint */ +#if defined(__MINT__) +#define DUK_F_MINT +#endif + /* - * Platform detection, system includes, Date provider selection. - * - * Feature selection (e.g. _XOPEN_SOURCE) must happen before any system - * headers are included. This header should avoid providing any feature - * selection defines when compiling user code (only when compiling Duktape - * itself). If a feature selection option is required for user code to - * compile correctly (e.g. it is needed for type detection), it should - * probably be -checked- here, not defined here. - * - * Date provider selection seems a bit out-of-place here, but since - * the date headers and provider functions are heavily platform - * specific, there's little point in duplicating the platform if-else - * ladder. All platform specific Date provider functions are in - * duk_bi_date.c; here we provide appropriate #defines to enable them, - * and include all the necessary system headers so that duk_bi_date.c - * compiles. Date "providers" are: - * - * NOW = getting current time (required) - * TZO = getting local time offset (required) - * PRS = parse datetime (optional) - * FMT = format datetime (optional) - * - * There's a lot of duplication here, unfortunately, because many - * platforms have similar (but not identical) headers, Date providers, - * etc. The duplication could be removed by more complicated nested - * #ifdefs, but it would then be more difficult to make fixes which - * affect only a specific platform. - * - * XXX: add a way to provide custom functions to provide the critical - * primitives; this would be convenient when porting to unknown platforms - * (rather than muck with Duktape internals). + * Platform autodetection */ -#if defined(DUK_COMPILING_DUKTAPE) && \ - (defined(DUK_F_LINUX) || defined(DUK_F_EMSCRIPTEN)) -/* A more recent Emscripten (2014-05) seems to lack "linux" environment - * defines, so check for Emscripten explicitly. - */ -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L -#endif -#ifndef _GNU_SOURCE -#define _GNU_SOURCE /* e.g. getdate_r */ -#endif -#ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE /* e.g. strptime */ -#endif -#endif - -#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE) -/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */ -#define _XOPEN_SOURCE 600 -#define _POSIX_C_SOURCE 200112L -#endif - -#undef DUK_F_MSVC_CRT_SECURE -#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) -/* http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx - * http://msdn.microsoft.com/en-us/library/wd3wzwts.aspx - * Seem to be available since VS2005. - */ -#if (_MSC_VER >= 1400) -/* VS2005+, secure CRT functions are preferred. Windows Store applications - * (and probably others) should use these. - */ -#define DUK_F_MSVC_CRT_SECURE -#endif -#if (_MSC_VER < 1700) -/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ -#define DUK_F_NO_STDINT_H -#endif -/* Initial fix: disable secure CRT related warnings when compiling Duktape - * itself (must be defined before including Windows headers). Don't define - * for user code including duktape.h. - */ -#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif -#endif /* DUK_F_WINDOWS && _MSC_VER */ - -#if defined(DUK_F_TOS) || defined(DUK_F_BCC) -#define DUK_F_NO_STDINT_H -#endif - /* Workaround for older C++ compilers before including , * see e.g.: https://sourceware.org/bugzilla/show_bug.cgi?id=15366 */ @@ -408,19 +353,35 @@ static __inline__ unsigned long long duk_rdtsc(void) { #define __STDC_CONSTANT_MACROS #endif -#if defined(__APPLE__) -/* Mac OSX, iPhone, Darwin */ +#if defined(DUK_F_APPLE) +/* --- Mac OSX, iPhone, Darwin --- */ #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R #define DUK_USE_DATE_PRS_STRPTIME #define DUK_USE_DATE_FMT_STRFTIME #include #include -#include #include #include #include + +/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */ +#if TARGET_IPHONE_SIMULATOR +#define DUK_USE_OS_STRING "iphone-sim" +#elif TARGET_OS_IPHONE +#define DUK_USE_OS_STRING "iphone" +#elif TARGET_OS_MAC +#define DUK_USE_OS_STRING "osx" +#else +#define DUK_USE_OS_STRING "osx-unknown" +#endif + +/* Use _setjmp() on Apple by default, see GH-55. */ +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) #elif defined(DUK_F_OPENBSD) +/* --- OpenBSD --- */ /* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */ #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R @@ -428,45 +389,52 @@ static __inline__ unsigned long long duk_rdtsc(void) { #define DUK_USE_DATE_FMT_STRFTIME #include #include -#include #include #include #include + +#define DUK_USE_OS_STRING "openbsd" #elif defined(DUK_F_BSD) -/* other BSD */ +/* --- Generic BSD --- */ #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R #define DUK_USE_DATE_PRS_STRPTIME #define DUK_USE_DATE_FMT_STRFTIME #include #include -#include #include #include #include + +#define DUK_USE_OS_STRING "bsd" #elif defined(DUK_F_TOS) -/* Atari ST TOS */ +/* --- Atari ST TOS --- */ #define DUK_USE_DATE_NOW_TIME #define DUK_USE_DATE_TZO_GMTIME /* no parsing (not an error) */ #define DUK_USE_DATE_FMT_STRFTIME -#include #include + +#define DUK_USE_OS_STRING "tos" + +/* TOS on M68K is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_M68K) +#define DUK_USE_BYTEORDER 3 +#endif #elif defined(DUK_F_AMIGAOS) +/* --- AmigaOS --- */ #if defined(DUK_F_M68K) /* AmigaOS on M68k */ #define DUK_USE_DATE_NOW_TIME #define DUK_USE_DATE_TZO_GMTIME /* no parsing (not an error) */ #define DUK_USE_DATE_FMT_STRFTIME -#include #include #elif defined(DUK_F_PPC) #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R #define DUK_USE_DATE_PRS_STRPTIME #define DUK_USE_DATE_FMT_STRFTIME -#include #include #ifndef UINTPTR_MAX #define UINTPTR_MAX UINT_MAX @@ -474,7 +442,23 @@ static __inline__ unsigned long long duk_rdtsc(void) { #else #error AmigaOS but not M68K/PPC, not supported now #endif + +#define DUK_USE_OS_STRING "amigaos" + +/* AmigaOS on M68K or PPC is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) +#define DUK_USE_BYTEORDER 3 +#endif #elif defined(DUK_F_WINDOWS) +/* --- Windows --- */ +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + /* Windows 32-bit and 64-bit are currently the same. */ /* MSVC does not have sys/param.h */ #define DUK_USE_DATE_NOW_WINDOWS @@ -484,129 +468,886 @@ static __inline__ unsigned long long duk_rdtsc(void) { * the ISO 8601 standard format. */ #if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ #include #endif -#include + +#define DUK_USE_OS_STRING "windows" + +/* On Windows, assume we're little endian. Even Itanium which has a + * configurable endianness runs little endian in Windows. + */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif #elif defined(DUK_F_FLASHPLAYER) -/* Crossbridge */ +/* --- Flashplayer (Crossbridge) --- */ #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R #define DUK_USE_DATE_PRS_STRPTIME #define DUK_USE_DATE_FMT_STRFTIME #include -#include #include #include #include + +#define DUK_USE_OS_STRING "flashplayer" + +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_FLASHPLAYER) +#define DUK_USE_BYTEORDER 1 +#endif #elif defined(DUK_F_QNX) -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include -#elif defined(DUK_F_TINSPIRE) -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include -#elif defined(DUK_F_LINUX) -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#if defined(DUK_F_BCC) -/* no endian.h */ -#else -#include -#endif /* DUK_F_BCC */ -#include -#include -#include -#include -#elif defined(__posix) -/* POSIX */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include -#include -#elif defined(DUK_F_CYGWIN) -/* Cygwin -- don't use strptime() for now */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_FMT_STRFTIME -#include -#include -#include -#include -#include -#include -#else -/* Other UNIX, hopefully others */ -#define DUK_USE_DATE_NOW_GETTIMEOFDAY -#define DUK_USE_DATE_TZO_GMTIME_R -#define DUK_USE_DATE_PRS_STRPTIME -#define DUK_USE_DATE_FMT_STRFTIME -#include -#if defined(DUK_F_BCC) -/* no endian.h */ -#else -#include -#endif /* DUK_F_BCC */ -#include -#include -#include -#include +/* --- QNX --- */ +#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE) +/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */ +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L #endif -/* Shared includes */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "qnx" +#elif defined(DUK_F_TINSPIRE) +/* --- TI-Nspire --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "tinspire" +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include +#if defined(DUK_F_BCC) +/* no endian.h */ +#else +#include +#endif /* DUK_F_BCC */ +#include +#include +#include +#include + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#define DUK_USE_OS_STRING "emscripten" +#elif defined(DUK_F_LINUX) +/* --- Linux --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include +#if defined(DUK_F_BCC) +/* no endian.h or stdint.h */ +#else +#include +#include +#endif /* DUK_F_BCC */ +#include +#include +#include + +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#define DUK_USE_OS_STRING "linux" +#elif defined(DUK_F_SUN) +/* --- Solaris --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME + +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "solaris" +#elif defined(DUK_F_POSIX) +/* --- Generic POSIX --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_USE_OS_STRING "posix" +#elif defined(DUK_F_CYGWIN) +/* --- Cygwin --- */ +/* don't use strptime() for now */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include +#include +#include + +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) + +#define DUK_USE_OS_STRING "windows" +#elif defined(DUK_F_UNIX) +/* --- Generic UNIX --- */ +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#define DUK_USE_OS_STRING "unknown" +#else +/* --- Generic fallback --- */ +/* The most portable current time provider is time(), but it only has a + * one second resolution. + */ +#define DUK_USE_DATE_NOW_TIME + +/* The most portable way to figure out local time offset is gmtime(), + * but it's not thread safe so use with caution. + */ +#define DUK_USE_DATE_TZO_GMTIME + +/* Avoid custom date parsing and formatting for portability. */ +#undef DUK_USE_DATE_PRS_STRPTIME +#undef DUK_USE_DATE_FMT_STRFTIME + +/* Rely on C89 headers only; time.h must be here. */ +#include + +#define DUK_USE_OS_STRING "unknown" +#endif /* autodetect platform */ + +/* Shared includes: C89 */ #include #include #include #include /* varargs */ #include #include /* e.g. ptrdiff_t */ +#include +#include + +/* date.h is omitted, and included per platform */ + +/* Shared includes: stdint.h is C99 */ #if defined(DUK_F_NO_STDINT_H) /* stdint.h not available */ #else -/* Technically C99 (C++11) but found in many systems. Note the workaround - * above for some C++ compilers (__STDC_LIMIT_MACROS etc). +/* Technically C99 (C++11) but found in many systems. On some systems + * __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS must be defined before + * including stdint.h (see above). */ #include #endif -#include -#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ - !defined(DUK_F_BCC) -/* ULL / LL preprocessor constants should be avoided because they're not - * always available. With suitable options, some compilers will support - * 64-bit integer types but won't support ULL / LL preprocessor constants. - * Assume C99/C++11 environments have these. However, BCC is nominally - * C99 but doesn't support these constants. - */ -#define DUK_F_ULL_CONSTS +#if defined(DUK_F_CPP) +#include /* std::exception */ #endif /* - * Detection for specific libc variants (like uclibc) and other libc specific - * features. Potentially depends on the #includes above. + * Architecture autodetection */ +#if defined(DUK_F_X86) +/* --- x86 --- */ +#define DUK_USE_ARCH_STRING "x86" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X64) +/* --- x64 --- */ +#define DUK_USE_ARCH_STRING "x64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X32) +/* --- x32 --- */ +#define DUK_USE_ARCH_STRING "x32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM32) +/* --- ARM 32-bit --- */ +#define DUK_USE_ARCH_STRING "arm32" +/* Byte order varies, so rely on autodetect. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM64) +/* --- ARM 64-bit --- */ +#define DUK_USE_ARCH_STRING "arm64" +/* Byte order varies, so rely on autodetect. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS32) +/* --- MIPS 32-bit --- */ +#define DUK_USE_ARCH_STRING "mips32" +/* MIPS byte order varies so rely on autodetection. */ +/* Based on 'make checkalign' there are no alignment requirements on + * Linux MIPS except for doubles, which need align by 4. Alignment + * requirements vary based on target though. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS64) +/* --- MIPS 64-bit --- */ +#define DUK_USE_ARCH_STRING "mips64" +/* MIPS byte order varies so rely on autodetection. */ +/* Good default is a bit arbitrary because alignment requirements + * depend on target. See https://github.com/svaarala/duktape/issues/102. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC32) +/* --- PowerPC 32-bit --- */ +#define DUK_USE_ARCH_STRING "ppc32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC64) +/* --- PowerPC 64-bit --- */ +#define DUK_USE_ARCH_STRING "ppc64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC32) +/* --- SPARC 32-bit --- */ +#define DUK_USE_ARCH_STRING "sparc32" +/* SPARC byte order varies so rely on autodetection. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC64) +/* --- SPARC 64-bit --- */ +#define DUK_USE_ARCH_STRING "sparc64" +/* SPARC byte order varies so rely on autodetection. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SUPERH) +/* --- SuperH --- */ +#define DUK_USE_ARCH_STRING "sh" +/* Byte order varies, rely on autodetection. */ +/* Based on 'make checkalign' there are no alignment requirements on + * Linux SH4, but align by 4 is probably a good basic default. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_M68K) +/* --- Motorola 68k --- */ +#define DUK_USE_ARCH_STRING "m68k" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_USE_ARCH_STRING "emscripten" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#else +/* --- Generic --- */ +/* These are necessary wild guesses. */ +#define DUK_USE_ARCH_STRING "generic" +/* Rely on autodetection for byte order, alignment, and packed tval. */ +#endif /* autodetect architecture */ + +/* + * Compiler autodetection + */ + +#if defined(DUK_F_CLANG) +/* --- Clang --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* Clang: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#else +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "clang" +#else +#define DUK_USE_COMPILER_STRING "clang" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR +#elif defined(DUK_F_GCC) +/* --- GCC --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* GCC: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 20500L) +/* since gcc-2.5 */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* since gcc-4.5 */ +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif + +#define DUK_USE_BRANCH_HINTS +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* GCC: test not very accurate; enable only in relatively recent builds + * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html) + */ +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) +#endif + +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#elif defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40000) +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_MINGW) +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "mingw++" +#else +#define DUK_USE_COMPILER_STRING "mingw" +#endif +#else +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "g++" +#else +#define DUK_USE_COMPILER_STRING "gcc" +#endif +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__)) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40600) +#define DUK_USE_GCC_PRAGMAS +#else +#undef DUK_USE_GCC_PRAGMAS +#endif + +#define DUK_USE_PACK_GCC_ATTR +#elif defined(DUK_F_MSVC) +/* --- MSVC --- */ +/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */ +#define DUK_NORETURN(decl) __declspec(noreturn) decl + +/* XXX: DUK_UNREACHABLE for msvc? */ + +#undef DUK_USE_BRANCH_HINTS + +/* XXX: DUK_LIKELY, DUK_UNLIKELY for msvc? */ +/* XXX: DUK_NOINLINE, DUK_INLINE, DUK_ALWAYS_INLINE for msvc? */ + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "msvc++" +#else +#define DUK_USE_COMPILER_STRING "msvc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) +#define DUK_USE_VARIADIC_MACROS +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +/* VS2005+ should have variadic macros even when they're not C99. */ +#define DUK_USE_VARIADIC_MACROS +#endif + +#undef DUK_USE_UNION_INITIALIZERS +#if defined(_MSC_VER) && (_MSC_VER >= 1800) +/* VS2013+ supports union initializers but there's a bug involving union-inside-struct: + * https://connect.microsoft.com/VisualStudio/feedback/details/805981 + * The bug was fixed (at least) in VS2015 so check for VS2015 for now: + * https://blogs.msdn.microsoft.com/vcblog/2015/07/01/c-compiler-front-end-fixes-in-vs2015/ + * Manually tested using VS2013, CL reports 18.00.31101, so enable for VS2013 too. + */ +#define DUK_USE_UNION_INITIALIZERS +#endif + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS + +#define DUK_USE_PACK_MSVC_PRAGMA + +/* These have been tested from VS2008 onwards; may work in older VS versions + * too but not enabled by default. + */ +#if defined(_MSC_VER) && (_MSC_VER >= 1500) +#define DUK_NOINLINE __declspec(noinline) +#define DUK_INLINE __inline +#define DUK_ALWAYS_INLINE __forceinline +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) +#define DUK_SNPRINTF snprintf +#define DUK_VSNPRINTF vsnprintf +#else +/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does + * NOT NUL terminate on truncation, but Duktape code never assumes that. + * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 + */ +#define DUK_SNPRINTF _snprintf +#define DUK_VSNPRINTF _vsnprintf +#endif +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and + * Clang. Based on documentation it should suffice to have the attribute + * in the declaration only, but in practice some warnings are generated unless + * the attribute is also applied to the definition. + */ +#define DUK_INTERNAL_DECL static __attribute__ ((unused)) +#define DUK_INTERNAL static __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#endif +#else +#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static + +#define DUK_USE_COMPILER_STRING "emscripten" + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_UNION_INITIALIZERS + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR +#elif defined(DUK_F_TINYC) +/* --- TinyC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "tinyc++" +#else +#define DUK_USE_COMPILER_STRING "tinyc" +#endif + +/* http://bellard.org/tcc/tcc-doc.html#SEC7 */ +#define DUK_USE_VARIADIC_MACROS + +#define DUK_USE_UNION_INITIALIZERS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#elif defined(DUK_F_VBCC) +/* --- VBCC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "vbcc-c++" +#else +#define DUK_USE_COMPILER_STRING "vbcc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +/* VBCC supports C99 so check only for C99 for union initializer support. + * Designated union initializers would possibly work even without a C99 check. + */ +#undef DUK_USE_UNION_INITIALIZERS +#if defined(DUK_F_C99) +#define DUK_USE_UNION_INITIALIZERS +#endif + +#define DUK_USE_FLEX_ZEROSIZE +#define DUK_USE_PACK_DUMMY_MEMBER +#elif defined(DUK_F_BCC) +/* --- Bruce's C compiler --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "bcc++" +#else +#define DUK_USE_COMPILER_STRING "bcc" +#endif + +/* Most portable */ +#undef DUK_USE_VARIADIC_MACROS + +/* Most portable, wastes space */ +#undef DUK_USE_UNION_INITIALIZERS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER + +/* BCC, assume we're on x86. */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#else +/* --- Generic --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "generic-c++" +#else +#define DUK_USE_COMPILER_STRING "generic" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +/* C++ doesn't have standard designated union initializers ({ .foo = 1 }). */ +#undef DUK_USE_UNION_INITIALIZERS +#if defined(DUK_F_C99) +#define DUK_USE_UNION_INITIALIZERS +#endif + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#endif /* autodetect compiler */ + +/* uclibc */ #if defined(__UCLIBC__) #define DUK_F_UCLIBC #endif @@ -654,10 +1395,11 @@ static __inline__ unsigned long long duk_rdtsc(void) { #error cannot check complement of two #endif -/* Pointer size determination based on architecture. - * XXX: unsure about BCC correctness. +/* Pointer size determination based on __WORDSIZE or architecture when + * that's not available. */ #if defined(DUK_F_X86) || defined(DUK_F_X32) || \ + defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ defined(DUK_F_BCC) || \ (defined(__WORDSIZE) && (__WORDSIZE == 32)) #define DUK_F_32BIT_PTRS @@ -1089,6 +1831,11 @@ typedef duk_int_t duk_idx_t; #define DUK_IDX_MIN DUK_INT_MIN #define DUK_IDX_MAX DUK_INT_MAX +/* Unsigned index variant. */ +typedef duk_uint_t duk_uidx_t; +#define DUK_UIDX_MIN DUK_UINT_MIN +#define DUK_UIDX_MAX DUK_UINT_MAX + /* Array index values, could be exact 32 bits. * Currently no need for signed duk_arridx_t. */ @@ -1149,11 +1896,9 @@ typedef double duk_double_t; /* Type for public API calls. */ typedef struct duk_hthread duk_context; -/* - * Check whether we should use 64-bit integers - */ - -/* Quite incomplete now. Use 64-bit types if detected (C99 or other detection) +/* Check whether we should use 64-bit integers or not. + * + * Quite incomplete now. Use 64-bit types if detected (C99 or other detection) * unless they are known to be unreliable. For instance, 64-bit types are * available on VBCC but seem to misbehave. */ @@ -1164,383 +1909,167 @@ typedef struct duk_hthread duk_context; #endif /* - * Alignment requirement and support for unaligned accesses + * Fill-ins for platform, architecture, and compiler + */ + +#if !defined(DUK_SETJMP) +#define DUK_JMPBUF_TYPE jmp_buf +#define DUK_SETJMP(jb) setjmp((jb)) +#define DUK_LONGJMP(jb) longjmp((jb), 1) +#endif + +#if 0 +/* sigsetjmp() alternative */ +#define DUK_JMPBUF_TYPE sigjmp_buf +#define DUK_SETJMP(jb) sigsetjmp((jb)) +#define DUK_LONGJMP(jb) siglongjmp((jb), 1) +#endif + +typedef FILE duk_file; +#if !defined(DUK_STDIN) +#define DUK_STDIN stdin +#endif +#if !defined(DUK_STDOUT) +#define DUK_STDOUT stdout +#endif +#if !defined(DUK_STDERR) +#define DUK_STDERR stderr +#endif + +/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h + * (which is unfortunately named). May sometimes need replacement, e.g. + * some compilers don't handle zero length or NULL correctly in realloc(). + */ +#if !defined(DUK_ANSI_MALLOC) +#define DUK_ANSI_MALLOC malloc +#endif +#if !defined(DUK_ANSI_REALLOC) +#define DUK_ANSI_REALLOC realloc +#endif +#if !defined(DUK_ANSI_CALLOC) +#define DUK_ANSI_CALLOC calloc +#endif +#if !defined(DUK_ANSI_FREE) +#define DUK_ANSI_FREE free +#endif + +/* ANSI C (various versions) and some implementations require that the + * pointer arguments to memset(), memcpy(), and memmove() be valid values + * even when byte size is 0 (even a NULL pointer is considered invalid in + * this context). Zero-size operations as such are allowed, as long as their + * pointer arguments point to a valid memory area. The DUK_MEMSET(), + * DUK_MEMCPY(), and DUK_MEMMOVE() macros require this same behavior, i.e.: + * (1) pointers must be valid and non-NULL, (2) zero size must otherwise be + * allowed. If these are not fulfilled, a macro wrapper is needed. * - * Assume unaligned accesses are not supported unless specifically allowed - * in the target platform. Some platforms may support unaligned accesses - * but alignment to 4 or 8 may still be desirable. - */ - -#undef DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#undef DUK_USE_ALIGN_BY - -#if defined(DUK_F_EMSCRIPTEN) -/* Required on at least some targets, so use whenever Emscripten used, - * regardless of compilation target. - */ -#define DUK_USE_ALIGN_BY 8 -#elif defined(DUK_F_ARM) -#define DUK_USE_ALIGN_BY 4 -#elif defined(DUK_F_MIPS32) -/* Based on 'make checkalign' there are no alignment requirements on - * Linux MIPS except for doubles, which need align by 4. Alignment - * requirements vary based on target though. - */ -#define DUK_USE_ALIGN_BY 4 -#elif defined(DUK_F_MIPS64) -/* Good default is a bit arbitrary because alignment requirements - * depend on target. See https://github.com/svaarala/duktape/issues/102. - */ -#define DUK_USE_ALIGN_BY 8 -#elif defined(DUK_F_SUPERH) -/* Based on 'make checkalign' there are no alignment requirements on - * Linux SH4, but align by 4 is probably a good basic default. - */ -#define DUK_USE_ALIGN_BY 4 -#elif defined(DUK_F_X86) || defined(DUK_F_X32) || defined(DUK_F_X64) || \ - defined(DUK_F_BCC) -/* XXX: This is technically not guaranteed because it's possible to configure - * an x86 to require aligned accesses with Alignment Check (AC) flag. - */ -#define DUK_USE_ALIGN_BY 1 -#define DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#else -/* Unknown, use safe default */ -#define DUK_USE_ALIGN_BY 8 -#endif - -/* User forced alignment to 4 or 8. */ -#if defined(DUK_OPT_FORCE_ALIGN) -#undef DUK_USE_ALIGN_BY -#undef DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#if (DUK_OPT_FORCE_ALIGN == 4) -#define DUK_USE_ALIGN_BY 4 -#elif (DUK_OPT_FORCE_ALIGN == 8) -#define DUK_USE_ALIGN_BY 8 -#else -#error invalid DUK_OPT_FORCE_ALIGN value -#endif -#endif - -/* Compiler specific hackery needed to force struct size to match aligment, - * see e.g. duk_hbuffer.h. + * http://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0 + * http://lists.cs.uiuc.edu/pipermail/llvmdev/2007-October/011065.html * - * http://stackoverflow.com/questions/11130109/c-struct-size-alignment - * http://stackoverflow.com/questions/10951039/specifying-64-bit-alignment - */ -#if defined(DUK_F_MSVC) -#define DUK_USE_PACK_MSVC_PRAGMA -#elif defined(DUK_F_GCC) -#define DUK_USE_PACK_GCC_ATTR -#elif defined(DUK_F_CLANG) -#define DUK_USE_PACK_CLANG_ATTR -#else -#define DUK_USE_PACK_DUMMY_MEMBER -#endif - -#ifdef DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#define DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS -#else -#undef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS -#endif - -/* Object property allocation layout has implications for memory and code - * footprint and generated code size/speed. The best layout also depends - * on whether the platform has alignment requirements or benefits from - * having mostly aligned accesses. - */ -#undef DUK_USE_HOBJECT_LAYOUT_1 -#undef DUK_USE_HOBJECT_LAYOUT_2 -#undef DUK_USE_HOBJECT_LAYOUT_3 -#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) && (DUK_USE_ALIGN_BY == 1) -/* On platforms without any alignment issues, layout 1 is preferable - * because it compiles to slightly less code and provides direct access - * to property keys. - */ -#define DUK_USE_HOBJECT_LAYOUT_1 -#else -/* On other platforms use layout 2, which requires some padding but - * is a bit more natural than layout 3 in ordering the entries. Layout - * 3 is currently not used. - */ -#define DUK_USE_HOBJECT_LAYOUT_2 -#endif - -/* - * Byte order and double memory layout detection + * Not sure what's the required behavior when a pointer points just past the + * end of a buffer, which often happens in practice (e.g. zero size memmoves). + * For example, if allocation size is 3, the following pointer would not + * technically point to a valid memory byte: * - * Endianness detection is a major portability hassle because the macros - * and headers are not standardized. There's even variance across UNIX - * platforms. Even with "standard" headers, details like underscore count - * varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used - * (Crossbridge has a single underscore, for instance). - * - * The checks below are structured with this in mind: several approaches are - * used, and at the end we check if any of them worked. This allows generic - * approaches to be tried first, and platform/compiler specific hacks tried - * last. As a last resort, the user can force a specific endianness, as it's - * not likely that automatic detection will work on the most exotic platforms. - * - * Duktape supports little and big endian machines. There's also support - * for a hybrid used by some ARM machines where integers are little endian - * but IEEE double values use a mixed order (12345678 -> 43218765). This - * byte order for doubles is referred to as "mixed endian". + * <-- alloc --> + * | 0 | 1 | 2 | ..... + * ^-- p=3, points after last valid byte (2) */ - -#undef DUK_F_BYTEORDER -#undef DUK_USE_BYTEORDER_FORCED - -/* DUK_F_BYTEORDER is set as an intermediate value when detection - * succeeds, to one of: - * 1 = little endian - * 2 = mixed (arm hybrid) endian - * 3 = big endian +#if !defined(DUK_MEMCPY) +#if defined(DUK_F_UCLIBC) +/* Old uclibcs have a broken memcpy so use memmove instead (this is overly wide + * now on purpose): http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html */ - -/* For custom platforms allow user to define byteorder explicitly. - * Since endianness headers are not standardized, this is a useful - * workaround for custom platforms for which endianness detection - * is not directly supported. Perhaps custom hardware is used and - * user cannot submit upstream patches. - */ -#if defined(DUK_OPT_FORCE_BYTEORDER) -#if (DUK_OPT_FORCE_BYTEORDER == 1) -#define DUK_F_BYTEORDER 1 -#elif (DUK_OPT_FORCE_BYTEORDER == 2) -#define DUK_F_BYTEORDER 2 -#elif (DUK_OPT_FORCE_BYTEORDER == 3) -#define DUK_F_BYTEORDER 3 +#define DUK_MEMCPY memmove #else -#error invalid DUK_OPT_FORCE_BYTEORDER value -#endif -#define DUK_USE_BYTEORDER_FORCED -#endif /* DUK_OPT_FORCE_BYTEORDER */ - -/* More or less standard endianness predefines provided by header files. - * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER - * will be big endian, see: http://lists.mysql.com/internals/443. - */ -#if !defined(DUK_F_BYTEORDER) -#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \ - defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \ - defined(__LITTLE_ENDIAN__) -/* Integer little endian */ -#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \ - defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN) -#define DUK_F_BYTEORDER 1 -#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ - defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) -#define DUK_F_BYTEORDER 2 -#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) -/* Float word order not known, assume not a hybrid. */ -#define DUK_F_BYTEORDER 1 -#else -/* byte order is little endian but cannot determine IEEE double word order */ -#endif /* float word order */ -#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \ - defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \ - defined(__BIG_ENDIAN__) -/* Integer big endian */ -#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ - defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) -#define DUK_F_BYTEORDER 3 -#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) -/* Float word order not known, assume not a hybrid. */ -#define DUK_F_BYTEORDER 3 -#else -/* byte order is big endian but cannot determine IEEE double word order */ -#endif /* float word order */ -#else -/* cannot determine byte order */ -#endif /* integer byte order */ -#endif /* !defined(DUK_F_BYTEORDER) */ - -/* GCC and Clang provide endianness defines as built-in predefines, with - * leading and trailing double underscores (e.g. __BYTE_ORDER__). See - * output of "make gccpredefs" and "make clangpredefs". Clang doesn't - * seem to provide __FLOAT_WORD_ORDER__. - * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html - */ -#if !defined(DUK_F_BYTEORDER) && defined(__BYTE_ORDER__) -#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -/* Integer little endian */ -#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ - (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#define DUK_F_BYTEORDER 1 -#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) -#define DUK_F_BYTEORDER 2 -#elif !defined(__FLOAT_WORD_ORDER__) -/* Float word order not known, assume not a hybrid. */ -#define DUK_F_BYTEORDER 1 -#else -/* byte order is little endian but cannot determine IEEE double word order */ -#endif /* float word order */ -#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -/* Integer big endian */ -#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) -#define DUK_F_BYTEORDER 3 -#elif !defined(__FLOAT_WORD_ORDER__) -/* Float word order not known, assume not a hybrid. */ -#define DUK_F_BYTEORDER 3 -#else -/* byte order is big endian but cannot determine IEEE double word order */ -#endif /* float word order */ -#else -/* cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit - * integer ordering and is not relevant - */ -#endif /* integer byte order */ -#endif /* !defined(DUK_F_BYTEORDER) && defined(__BYTE_ORDER__) */ - -/* Atari ST TOS */ -#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_TOS) -#define DUK_F_BYTEORDER 3 -#endif - -/* AmigaOS on M68K or PPC */ -#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_AMIGAOS) -#if defined(DUK_F_M68K) || defined(DUK_F_PPC) -#define DUK_F_BYTEORDER 3 +#define DUK_MEMCPY memcpy #endif #endif - -/* On Windows, assume we're little endian. Even Itanium which has a - * configurable endianness runs little endian in Windows. - */ -#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_WINDOWS) -/* XXX: verify that Windows on ARM is little endian for floating point - * values too. - */ -#define DUK_F_BYTEORDER 1 -#endif /* Windows */ - -/* Crossbridge should work with the standard byteorder #ifdefs. It doesn't - * provide _FLOAT_WORD_ORDER but the standard approach now covers that case - * too. This has been left here just in case. - */ -#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_FLASHPLAYER) -#define DUK_F_BYTEORDER 1 +#if !defined(DUK_MEMMOVE) +#define DUK_MEMMOVE memmove +#endif +#if !defined(DUK_MEMCMP) +#define DUK_MEMCMP memcmp +#endif +#if !defined(DUK_MEMSET) +#define DUK_MEMSET memset +#endif +#if !defined(DUK_STRLEN) +#define DUK_STRLEN strlen +#endif +#if !defined(DUK_STRCMP) +#define DUK_STRCMP strcmp +#endif +#if !defined(DUK_STRNCMP) +#define DUK_STRNCMP strncmp +#endif +#if !defined(DUK_PRINTF) +#define DUK_PRINTF printf +#endif +#if !defined(DUK_FPRINTF) +#define DUK_FPRINTF fprintf +#endif +#if !defined(DUK_SPRINTF) +#define DUK_SPRINTF sprintf +#endif +#if !defined(DUK_SNPRINTF) +/* snprintf() is technically not part of C89 but usually available. */ +#define DUK_SNPRINTF snprintf +#endif +#if !defined(DUK_VSPRINTF) +#define DUK_VSPRINTF vsprintf +#endif +#if !defined(DUK_VSNPRINTF) +/* vsnprintf() is technically not part of C89 but usually available. */ +#define DUK_VSNPRINTF vsnprintf +#endif +#if !defined(DUK_SSCANF) +#define DUK_SSCANF sscanf +#endif +#if !defined(DUK_VSSCANF) +#define DUK_VSSCANF vsscanf +#endif +#if !defined(DUK_FOPEN) +#define DUK_FOPEN fopen +#endif +#if !defined(DUK_FCLOSE) +#define DUK_FCLOSE fclose +#endif +#if !defined(DUK_FREAD) +#define DUK_FREAD fread +#endif +#if !defined(DUK_FWRITE) +#define DUK_FWRITE fwrite +#endif +#if !defined(DUK_FSEEK) +#define DUK_FSEEK fseek +#endif +#if !defined(DUK_FTELL) +#define DUK_FTELL ftell +#endif +#if !defined(DUK_FFLUSH) +#define DUK_FFLUSH fflush +#endif +#if !defined(DUK_FPUTC) +#define DUK_FPUTC fputc +#endif +#if !defined(DUK_MEMZERO) +#define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n)) +#endif +#if !defined(DUK_ABORT) +#define DUK_ABORT abort +#endif +#if !defined(DUK_EXIT) +#define DUK_EXIT exit #endif -/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__: - * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - - * | 0 | 1 | 2 | ..... - * ^-- p=3, points after last valid byte (2) - * - * If this is a practical issue, wrappers are again needed. + * Duktape supports little and big endian machines. There's also support + * for a hybrid used by some ARM machines where integers are little endian + * but IEEE double values use a mixed order (12345678 -> 43218765). This + * byte order for doubles is referred to as "mixed endian". */ -typedef FILE duk_file; -#define DUK_STDIN stdin -#define DUK_STDOUT stdout -#define DUK_STDERR stderr - -/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h - * (which is unfortunately named). +/* For custom platforms allow user to define byteorder explicitly. + * Since endianness headers are not standardized, this is a useful + * workaround for custom platforms for which endianness detection + * is not directly supported. Perhaps custom hardware is used and + * user cannot submit upstream patches. */ -#define DUK_ANSI_MALLOC malloc -#define DUK_ANSI_REALLOC realloc -#define DUK_ANSI_CALLOC calloc -#define DUK_ANSI_FREE free - -/* Old uclibcs have a broken memcpy so use memmove instead (this is overly - * wide now on purpose): - * http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html - */ -#if defined(DUK_F_UCLIBC) -#define DUK_MEMCPY memmove +#if defined(DUK_OPT_FORCE_BYTEORDER) +#undef DUK_USE_BYTEORDER +#if (DUK_OPT_FORCE_BYTEORDER == 1) +#define DUK_USE_BYTEORDER 1 +#elif (DUK_OPT_FORCE_BYTEORDER == 2) +#define DUK_USE_BYTEORDER 2 +#elif (DUK_OPT_FORCE_BYTEORDER == 3) +#define DUK_USE_BYTEORDER 3 #else -#define DUK_MEMCPY memcpy +#error invalid DUK_OPT_FORCE_BYTEORDER value #endif +#endif /* DUK_OPT_FORCE_BYTEORDER */ -#define DUK_MEMMOVE memmove -#define DUK_MEMCMP memcmp -#define DUK_MEMSET memset -#define DUK_STRLEN strlen -#define DUK_STRCMP strcmp -#define DUK_STRNCMP strncmp -#define DUK_PRINTF printf -#define DUK_FPRINTF fprintf -#define DUK_SPRINTF sprintf - -#if defined(DUK_F_MSVC) -/* _snprintf() does NOT NUL terminate on truncation, but Duktape code never - * assumes that. - * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 +/* GCC and Clang provide endianness defines as built-in predefines, with + * leading and trailing double underscores (e.g. __BYTE_ORDER__). See + * output of "make gccpredefs" and "make clangpredefs". Clang doesn't + * seem to provide __FLOAT_WORD_ORDER__; assume not mixed endian for clang. + * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html */ -#define DUK_SNPRINTF _snprintf +#if !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) +#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 #else -#define DUK_SNPRINTF snprintf +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit + * integer ordering and is not relevant. + */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) */ + +/* More or less standard endianness predefines provided by header files. + * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER + * will be big endian, see: http://lists.mysql.com/internals/443. + * On some platforms some defines may be present with an empty value which + * causes comparisons to fail: https://github.com/svaarala/duktape/issues/453. + */ +#if !defined(DUK_USE_BYTEORDER) +#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \ + defined(__LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 +#else +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order. */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) */ + +/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__: + * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - = 20500L) -/* since gcc-2.5 */ -#define DUK_NORETURN(decl) decl __attribute__((noreturn)) -#elif defined(__clang__) -/* syntax same as gcc */ -#define DUK_NORETURN(decl) decl __attribute__((noreturn)) -#elif defined(DUK_F_MSVC) -/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */ -#define DUK_NORETURN(decl) __declspec(noreturn) decl -#else -/* Don't know how to declare a noreturn function, so don't do it; this - * may cause some spurious compilation warnings (e.g. "variable used - * uninitialized"). +#define DUK_CAUSE_SEGFAULT() do { *((volatile duk_uint32_t *) NULL) = (duk_uint32_t) 0xdeadbeefUL; } while (0) +#endif +#if !defined(DUK_UNREF) +/* Macro for suppressing warnings for potentially unreferenced variables. + * The variables can be actually unreferenced or unreferenced in some + * specific cases only; for instance, if a variable is only debug printed, + * it is unreferenced when debug printing is disabled. */ +#define DUK_UNREF(x) do { (void) (x); } while (0) +#endif +#if !defined(DUK_NORETURN) #define DUK_NORETURN(decl) decl #endif - -/* - * Macro for stating that a certain line cannot be reached. - * - * http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Other-Builtins.html#Other-Builtins - * http://clang.llvm.org/docs/LanguageExtensions.html - */ - -#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) -/* since gcc-4.5 */ -#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while(0) -#elif defined(__clang__) && defined(__has_builtin) -#if __has_builtin(__builtin_unreachable) -/* same as gcc */ -#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while(0) -#endif -#else -/* unknown */ -#endif - #if !defined(DUK_UNREACHABLE) /* Don't know how to declare unreachable point, so don't do it; this * may cause some spurious compilation warnings (e.g. "variable used * uninitialized"). */ -#define DUK_UNREACHABLE() /* unreachable */ +#define DUK_UNREACHABLE() do { } while (0) #endif - -/* - * Likely and unlikely branches. Using these is not at all a clear cut case, - * so the selection is a two-step process: (1) DUK_USE_BRANCH_HINTS is set - * if the architecture, compiler etc make it useful to use the hints, and (2) - * a separate check determines how to do them. - * - * These macros expect the argument to be a relational expression with an - * integer value. If used with pointers, you should use an explicit check - * like: - * - * if (DUK_LIKELY(ptr != NULL)) { ... } - * - * instead of: - * - * if (DUK_LIKELY(ptr)) { ... } - * - * http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html (__builtin_expect) +#if !defined(DUK_LOSE_CONST) +/* Convert any input pointer into a "void *", losing a const qualifier. + * This is not fully portable because casting through duk_uintptr_t may + * not work on all architectures (e.g. those with long, segmented pointers). */ - -/* pretty much a placeholder now */ -#if defined(DUK_F_GCC) -#define DUK_USE_BRANCH_HINTS -#elif defined(DUK_F_CLANG) -#define DUK_USE_BRANCH_HINTS -#else -#undef DUK_USE_BRANCH_HINTS +#define DUK_LOSE_CONST(src) ((void *) (duk_uintptr_t) (src)) #endif -#if defined(DUK_USE_BRANCH_HINTS) -#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) -/* GCC: test not very accurate; enable only in relatively recent builds - * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html) - */ -#define DUK_LIKELY(x) __builtin_expect((x), 1) -#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -#elif defined(DUK_F_CLANG) -#define DUK_LIKELY(x) __builtin_expect((x), 1) -#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -#endif -#endif /* DUK_USE_BRANCH_HINTS */ - #if !defined(DUK_LIKELY) #define DUK_LIKELY(x) (x) #endif @@ -1997,36 +2518,94 @@ typedef FILE duk_file; #define DUK_UNLIKELY(x) (x) #endif -/* - * Function inlining control - * - * DUK_NOINLINE: avoid inlining a function. - * DUK_INLINE: suggest inlining a function. - * DUK_ALWAYS_INLINE: force inlining for critical functions. - * - * Apply to function definition only (not declaration). - */ - -#if defined(DUK_F_CLANG) && (defined(DUK_F_C99) || defined(DUK_F_CPP11)) -#define DUK_NOINLINE __attribute__((noinline)) -#define DUK_INLINE inline -#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) -#elif defined(DUK_F_GCC) && defined(DUK_F_GCC_VERSION) && (defined(DUK_F_C99) || defined(DUK_F_CPP11)) -#if (DUK_F_GCC_VERSION >= 30101) -#define DUK_NOINLINE __attribute__((noinline)) -#define DUK_INLINE inline -#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) -#endif -#endif - #if !defined(DUK_NOINLINE) #define DUK_NOINLINE /*nop*/ +#endif +#if !defined(DUK_INLINE) #define DUK_INLINE /*nop*/ +#endif +#if !defined(DUK_ALWAYS_INLINE) #define DUK_ALWAYS_INLINE /*nop*/ #endif -/* Temporary workaround for GH-323: avoid inlining control when - * compiling from multiple sources, as it causes compiler trouble. +#if !defined(DUK_EXTERNAL_DECL) +#define DUK_EXTERNAL_DECL extern +#endif +#if !defined(DUK_EXTERNAL) +#define DUK_EXTERNAL /*empty*/ +#endif +#if !defined(DUK_INTERNAL_DECL) +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#else +#define DUK_INTERNAL_DECL extern +#endif +#endif +#if !defined(DUK_INTERNAL) +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL /*empty*/ +#endif +#endif +#if !defined(DUK_LOCAL_DECL) +#define DUK_LOCAL_DECL static +#endif +#if !defined(DUK_LOCAL) +#define DUK_LOCAL static +#endif + +#if !defined(DUK_FILE_MACRO) +#define DUK_FILE_MACRO __FILE__ +#endif +#if !defined(DUK_LINE_MACRO) +#define DUK_LINE_MACRO __LINE__ +#endif +#if !defined(DUK_FUNC_MACRO) +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_FUNC_MACRO __func__ +#elif defined(__FUNCTION__) +#define DUK_FUNC_MACRO __FUNCTION__ +#else +#define DUK_FUNC_MACRO "unknown" +#endif +#endif + +#if !defined(DUK_BSWAP32) +#define DUK_BSWAP32(x) \ + ((((duk_uint32_t) (x)) >> 24) | \ + ((((duk_uint32_t) (x)) >> 8) & 0xff00UL) | \ + ((((duk_uint32_t) (x)) << 8) & 0xff0000UL) | \ + (((duk_uint32_t) (x)) << 24)) +#endif +#if !defined(DUK_BSWAP16) +#define DUK_BSWAP16(x) \ + ((duk_uint16_t) (x) >> 8) | \ + ((duk_uint16_t) (x) << 8) +#endif + +/* DUK_USE_VARIADIC_MACROS: required from compilers, so no fill-in. */ +/* DUK_USE_UNION_INITIALIZERS: required from compilers, so no fill-in. */ + +#if !(defined(DUK_USE_FLEX_C99) || defined(DUK_USE_FLEX_ZEROSIZE) || defined(DUK_USE_FLEX_ONESIZE)) +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE /* Not standard but common enough */ +#endif +#endif + +#if !(defined(DUK_USE_PACK_GCC_ATTR) || defined(DUK_USE_PACK_CLANG_ATTR) || \ + defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_DUMMY_MEMBER)) +#define DUK_USE_PACK_DUMMY_MEMBER +#endif + +#if 0 /* not defined by default */ +#undef DUK_USE_GCC_PRAGMAS +#endif + +/* Workaround for GH-323: avoid inlining control when compiling from + * multiple sources, as it causes compiler portability trouble. */ #if !defined(DUK_SINGLE_FILE) #undef DUK_NOINLINE @@ -2038,303 +2617,381 @@ typedef FILE duk_file; #endif /* - * Symbol visibility macros - * - * To avoid C++ declaration issues (see GH-63): - * - * - Don't use DUK_LOCAL_DECL for local -data symbols- so that you don't - * end up with both a "static" declaration and a definition. - * - * - Wrap any DUK_INTERNAL_DECL with a '#if !defined(DUK_SINGLE_FILE)' - * so that the internal declarations (which would map to "static" in - * a single file distribution) get dropped. + * Check whether or not a packed duk_tval representation is possible. + * What's basically required is that pointers are 32-bit values + * (sizeof(void *) == 4). Best effort check, not always accurate. + * If guess goes wrong, crashes may result; self tests also verify + * the guess. */ -/* XXX: user override for these? user override for just using the default visibility macros? */ -/* XXX: separate macros for function and data may be necessary at some point. */ +/* Explicit marker needed; may be 'defined', 'undefined, 'or 'not provided'. */ +#if !defined(DUK_F_PACKED_TVAL_PROVIDED) +#undef DUK_F_PACKED_TVAL_POSSIBLE -#if defined(DUK_F_GCC_VERSION) -#if (DUK_F_GCC_VERSION >= 40000) && !(defined(DUK_F_MINGW) || defined(DUK_F_CYGWIN)) -/* Might work on earlier versions too but limit to GCC 4+. - * MinGW should use Windows specific __declspec or no visibility attributes at all, - * otherwise: "warning: visibility attribute not supported in this configuration; ignored". - * Same applies to Cygwin GCC. - */ -#define DUK_F_GCC_SYMBOL_VISIBILITY -#endif -#endif -#if defined(DUK_F_CLANG) && !defined(DUK_F_GCC_SYMBOL_VISIBILITY) -#define DUK_F_GCC_SYMBOL_VISIBILITY -#endif -#if defined(DUK_OPT_DLL_BUILD) && defined(_WIN32) && (defined(_MSC_VER) || defined(__GNUC__)) -/* __declspec(dllexport) and __declspec(dllimport) only for Windows DLL build. - * MSVC: any minimum version? - * MinGW: no minimum version, even gcc-2.95.3 supported dllimport/dllexport. -*/ -#define DUK_F_MSVC_DLL_SYMBOL_VISIBILITY -#endif - -#if defined(DUK_F_GCC_SYMBOL_VISIBILITY) -/* GCC 4+ visibility attributes. */ -#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern -#define DUK_EXTERNAL __attribute__ ((visibility("default"))) -#if defined(DUK_SINGLE_FILE) -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#else -#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern -#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) -#endif -#elif defined(DUK_F_MSVC_DLL_SYMBOL_VISIBILITY) -/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're - * compiling Duktape or the application. - */ -#if defined(DUK_COMPILING_DUKTAPE) -#define DUK_EXTERNAL_DECL extern __declspec(dllexport) -#define DUK_EXTERNAL __declspec(dllexport) -#else -#define DUK_EXTERNAL_DECL extern __declspec(dllimport) -#define DUK_EXTERNAL should_not_happen -#endif -#if defined(DUK_SINGLE_FILE) -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#else -#define DUK_INTERNAL_DECL extern -#define DUK_INTERNAL /*empty*/ -#endif -#else -/* Default visibility. */ -#define DUK_EXTERNAL_DECL extern -#define DUK_EXTERNAL /*empty*/ -#if defined(DUK_SINGLE_FILE) -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#else /* DUK_SINGLE_FILE */ -#define DUK_INTERNAL_DECL extern -#define DUK_INTERNAL /*empty*/ +/* Strict C99 case: DUK_UINTPTR_MAX (= UINTPTR_MAX) should be very reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE #endif #endif -/* For now, these are shared. */ -#define DUK_LOCAL_DECL static -#define DUK_LOCAL static - -/* - * __FILE__, __LINE__, __func__ are wrapped. Especially __func__ is a - * problem because it is not available even in some compilers which try - * to be C99 compatible (e.g. VBCC with -c99 option). - */ - -#define DUK_FILE_MACRO __FILE__ - -#define DUK_LINE_MACRO __LINE__ - -#if !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) -#define DUK_FUNC_MACRO __func__ -#else -#define DUK_FUNC_MACRO "unknown" +/* Non-C99 case, still relying on DUK_UINTPTR_MAX, as long as it is not a computed value */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif #endif -/* - * Byteswap macros - * - * These are here so that inline assembly or other platform functions can be - * used if available. - */ - -#define DUK_BSWAP32(x) \ - ((((duk_uint32_t) (x)) >> 24) | \ - ((((duk_uint32_t) (x)) >> 8) & 0xff00UL) | \ - ((((duk_uint32_t) (x)) << 8) & 0xff0000UL) | \ - (((duk_uint32_t) (x)) << 24)) - -#define DUK_BSWAP16(x) \ - ((duk_uint16_t) (x) >> 8) | \ - ((duk_uint16_t) (x) << 8) - -/* - * Architecture string, human readable value exposed in Duktape.env - */ - -#if defined(DUK_F_X86) -#define DUK_USE_ARCH_STRING "x86" -#elif defined(DUK_F_X32) -#define DUK_USE_ARCH_STRING "x32" -#elif defined(DUK_F_X64) -#define DUK_USE_ARCH_STRING "x64" -#elif defined(DUK_F_ARM) -#define DUK_USE_ARCH_STRING "arm" -#elif defined(DUK_F_MIPS32) -#define DUK_USE_ARCH_STRING "mips32" -#elif defined(DUK_F_MIPS64) -#define DUK_USE_ARCH_STRING "mips64" -#elif defined(DUK_F_SUPERH) -#define DUK_USE_ARCH_STRING "sh" -#elif defined(DUK_F_PPC) -#define DUK_USE_ARCH_STRING "ppc" -#elif defined(DUK_F_M68K) -#define DUK_USE_ARCH_STRING "m68k" -#elif defined(DUK_F_FLASHPLAYER) -#define DUK_USE_ARCH_STRING "flashplayer" -#elif defined(DUK_F_EMSCRIPTEN) -#define DUK_USE_ARCH_STRING "emscripten" -#else -#define DUK_USE_ARCH_STRING "unknown" +/* DUK_SIZE_MAX (= SIZE_MAX) is often reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED) +#if (DUK_SIZE_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE #endif - -/* - * OS string, human readable value exposed in Duktape.env - */ - -#if defined(DUK_F_LINUX) -#define DUK_USE_OS_STRING "linux" -#elif defined(__APPLE__) -/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */ -#if TARGET_IPHONE_SIMULATOR -#define DUK_USE_OS_STRING "iphone-sim" -#elif TARGET_OS_IPHONE -#define DUK_USE_OS_STRING "iphone" -#elif TARGET_OS_MAC -#define DUK_USE_OS_STRING "ios" -#else -#define DUK_USE_OS_STRING "ios-unknown" #endif -#elif defined(DUK_F_FREEBSD) -#define DUK_USE_OS_STRING "freebsd" -#elif defined(DUK_F_OPENBSD) -#define DUK_USE_OS_STRING "openbsd" -#elif defined(DUK_F_NETBSD) -#define DUK_USE_OS_STRING "netbsd" -#elif defined(DUK_F_BSD) -#define DUK_USE_OS_STRING "bsd" -#elif defined(DUK_F_UNIX) -#define DUK_USE_OS_STRING "unix" -#elif defined(DUK_F_WINDOWS) -#define DUK_USE_OS_STRING "windows" -#elif defined(DUK_F_TOS) -#define DUK_USE_OS_STRING "tos" -#elif defined(DUK_F_AMIGAOS) -#define DUK_USE_OS_STRING "amigaos" -#elif defined(DUK_F_QNX) -#define DUK_USE_OS_STRING "qnx" -#elif defined(DUK_F_TINSPIRE) -#define DUK_USE_OS_STRING "tinspire" -#else -#define DUK_USE_OS_STRING "unknown" -#endif - -/* - * Compiler string, human readable value exposed in Duktape.env - */ - -#if defined(DUK_F_MINGW) -#define DUK_USE_COMPILER_STRING "mingw" -#elif defined(DUK_F_GCC) -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "g++" -#else -#define DUK_USE_COMPILER_STRING "gcc" -#endif -#elif defined(DUK_F_CLANG) -#define DUK_USE_COMPILER_STRING "clang" -#elif defined(DUK_F_MSVC) -#define DUK_USE_COMPILER_STRING "msvc" -#elif defined(DUK_F_VBCC) -#define DUK_USE_COMPILER_STRING "vbcc" -#else -#define DUK_USE_COMPILER_STRING "unknown" -#endif - -/* - * Target info string - */ - -#if defined(DUK_OPT_TARGET_INFO) -#define DUK_USE_TARGET_INFO DUK_OPT_TARGET_INFO -#else -#define DUK_USE_TARGET_INFO "unknown" -#endif - -/* - * Long control transfer, setjmp/longjmp or alternatives - * - * Signal mask is not saved (when that can be communicated to the platform) - */ - -/* dummy non-zero value to be used as an argument for longjmp(), see man longjmp */ -#define DUK_LONGJMP_DUMMY_VALUE 1 - -#if defined(DUK_OPT_SETJMP) -#define DUK_USE_SETJMP -#elif defined(DUK_OPT_UNDERSCORE_SETJMP) -#define DUK_USE_UNDERSCORE_SETJMP -#elif defined(DUK_OPT_SIGSETJMP) -#define DUK_USE_SIGSETJMP -#elif defined(__APPLE__) -/* Use _setjmp() on Apple by default, see GH-55. */ -#define DUK_USE_UNDERSCORE_SETJMP -#else -/* The most portable default is setjmp(). */ -#define DUK_USE_SETJMP -#endif - -#if defined(DUK_USE_UNDERSCORE_SETJMP) -#define DUK_SETJMP(jb) _setjmp((jb)) -#define DUK_LONGJMP(jb) _longjmp((jb), DUK_LONGJMP_DUMMY_VALUE) -#elif defined(DUK_USE_SIGSETJMP) -#define DUK_SETJMP(jb) sigsetjmp((jb), 0 /*savesigs*/) -#define DUK_LONGJMP(jb) siglongjmp((jb), DUK_LONGJMP_DUMMY_VALUE) -#elif defined(DUK_USE_SETJMP) -#define DUK_SETJMP(jb) setjmp((jb)) -#define DUK_LONGJMP(jb) longjmp((jb), DUK_LONGJMP_DUMMY_VALUE) -#else -#error internal error -#endif - -/* - * Speed/size and other performance options - */ - -/* Use fast ("inline") refcount operations instead of calling out to helpers - * by default. The difference in binary size is small (~1kB on x64). - */ -#define DUK_USE_FAST_REFCOUNT_DEFAULT - -/* Assert for valstack space but don't check for it in non-assert build. - * Valstack overruns (writing beyond checked space) is memory unsafe and - * potentially a segfault. Produces a smaller and faster binary. - * (In practice the speed difference is small with -O3 so default to - * safer behavior for now.) - */ -#undef DUK_USE_VALSTACK_UNSAFE - -/* Catch-all flag which can be used to choose between variant algorithms - * where a speed-size tradeoff exists (e.g. lookup tables). When it really - * matters, specific use flags may be appropriate. - */ -#define DUK_USE_PREFER_SIZE - -/* Use a sliding window for lexer; slightly larger footprint, slightly faster. */ -#define DUK_USE_LEXER_SLIDING_WINDOW - -/* Transparent JSON.stringify() fastpath. */ -#undef DUK_USE_JSON_STRINGIFY_FASTPATH -#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH) -#define DUK_USE_JSON_STRINGIFY_FASTPATH -#endif - -/* - * Tagged type representation (duk_tval) - */ #undef DUK_USE_PACKED_TVAL -#undef DUK_USE_FULL_TVAL - -#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) && !defined(DUK_OPT_NO_PACKED_TVAL) +#if defined(DUK_F_PACKED_TVAL_POSSIBLE) #define DUK_USE_PACKED_TVAL #endif +#undef DUK_F_PACKED_TVAL_POSSIBLE +#endif /* DUK_F_PACKED_TVAL_PROVIDED */ + +/* Feature option forcing. */ +#if defined(DUK_OPT_NO_PACKED_TVAL) +#undef DUK_USE_PACKED_TVAL +#elif defined(DUK_OPT_PACKED_TVAL) +#undef DUK_USE_PACKED_TVAL +#define DUK_USE_PACKED_TVAL +#endif +/* Object property allocation layout has implications for memory and code + * footprint and generated code size/speed. The best layout also depends + * on whether the platform has alignment requirements or benefits from + * having mostly aligned accesses. + */ +#undef DUK_USE_HOBJECT_LAYOUT_1 +#undef DUK_USE_HOBJECT_LAYOUT_2 +#undef DUK_USE_HOBJECT_LAYOUT_3 +#if (DUK_USE_ALIGN_BY == 1) +/* On platforms without any alignment issues, layout 1 is preferable + * because it compiles to slightly less code and provides direct access + * to property keys. + */ +#define DUK_USE_HOBJECT_LAYOUT_1 +#else +/* On other platforms use layout 2, which requires some padding but + * is a bit more natural than layout 3 in ordering the entries. Layout + * 3 is currently not used. + */ +#define DUK_USE_HOBJECT_LAYOUT_2 +#endif + +/* GCC/clang inaccurate math would break compliance and probably duk_tval, + * so refuse to compile. Relax this if -ffast-math is tested to work. + */ +#if defined(__FAST_MATH__) +#error __FAST_MATH__ defined, refusing to compile +#endif + +/* + * Feature option handling + */ + +#if !defined(DUK_USE_ALIGN_BY) +#if defined(DUK_OPT_FORCE_ALIGN) +#define DUK_USE_ALIGN_BY DUK_OPT_FORCE_ALIGN +#else +#define DUK_USE_ALIGN_BY 8 +#endif +#endif + +#if defined(DUK_OPT_ASSERTIONS) +#define DUK_USE_ASSERTIONS +#elif defined(DUK_OPT_NO_ASSERTIONS) +#undef DUK_USE_ASSERTIONS +#else +#undef DUK_USE_ASSERTIONS +#endif + +#if defined(DUK_OPT_AUGMENT_ERRORS) +#define DUK_USE_AUGMENT_ERROR_CREATE +#elif defined(DUK_OPT_NO_AUGMENT_ERRORS) +#undef DUK_USE_AUGMENT_ERROR_CREATE +#else +#define DUK_USE_AUGMENT_ERROR_CREATE +#endif + +#if defined(DUK_OPT_AUGMENT_ERRORS) +#define DUK_USE_AUGMENT_ERROR_THROW +#elif defined(DUK_OPT_NO_AUGMENT_ERRORS) +#undef DUK_USE_AUGMENT_ERROR_THROW +#else +#define DUK_USE_AUGMENT_ERROR_THROW +#endif + +#if defined(DUK_OPT_BROWSER_LIKE) +#define DUK_USE_BROWSER_LIKE +#elif defined(DUK_OPT_NO_BROWSER_LIKE) +#undef DUK_USE_BROWSER_LIKE +#else +#define DUK_USE_BROWSER_LIKE +#endif + +#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT) +#define DUK_USE_BUFFEROBJECT_SUPPORT +#elif defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT) +#undef DUK_USE_BUFFEROBJECT_SUPPORT +#else +#define DUK_USE_BUFFEROBJECT_SUPPORT +#endif + +#if defined(DUK_OPT_BUFLEN16) +#define DUK_USE_BUFLEN16 +#elif defined(DUK_OPT_NO_BUFLEN16) +#undef DUK_USE_BUFLEN16 +#else +#undef DUK_USE_BUFLEN16 +#endif + +#if defined(DUK_OPT_BYTECODE_DUMP_SUPPORT) +#define DUK_USE_BYTECODE_DUMP_SUPPORT +#elif defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT) +#undef DUK_USE_BYTECODE_DUMP_SUPPORT +#else +#define DUK_USE_BYTECODE_DUMP_SUPPORT +#endif + +#if defined(DUK_OPT_COMMONJS_MODULES) +#define DUK_USE_COMMONJS_MODULES +#elif defined(DUK_OPT_NO_COMMONJS_MODULES) +#undef DUK_USE_COMMONJS_MODULES +#else +#define DUK_USE_COMMONJS_MODULES +#endif + +#if defined(DUK_OPT_CPP_EXCEPTIONS) +#define DUK_USE_CPP_EXCEPTIONS +#elif defined(DUK_OPT_NO_CPP_EXCEPTIONS) +#undef DUK_USE_CPP_EXCEPTIONS +#else +#undef DUK_USE_CPP_EXCEPTIONS +#endif + +#if defined(DUK_OPT_DATAPTR16) +#define DUK_USE_DATAPTR16 +#elif defined(DUK_OPT_NO_DATAPTR16) +#undef DUK_USE_DATAPTR16 +#else +#undef DUK_USE_DATAPTR16 +#endif + +#if defined(DUK_OPT_DATAPTR_DEC16) +#define DUK_USE_DATAPTR_DEC16(udata,ptr) DUK_OPT_DATAPTR_DEC16((udata),(ptr)) +#else +#undef DUK_USE_DATAPTR_DEC16 +#endif + +#if defined(DUK_OPT_DATAPTR_ENC16) +#define DUK_USE_DATAPTR_ENC16(udata,ptr) DUK_OPT_DATAPTR_ENC16((udata),(ptr)) +#else +#undef DUK_USE_DATAPTR_ENC16 +#endif + +#if defined(DUK_OPT_DDDPRINT) +#define DUK_USE_DDDPRINT +#elif defined(DUK_OPT_NO_DDDPRINT) +#undef DUK_USE_DDDPRINT +#else +#undef DUK_USE_DDDPRINT +#endif + +#if defined(DUK_OPT_DDPRINT) +#define DUK_USE_DDPRINT +#elif defined(DUK_OPT_NO_DDPRINT) +#undef DUK_USE_DDPRINT +#else +#undef DUK_USE_DDPRINT +#endif + +#if defined(DUK_OPT_DEBUG) +#define DUK_USE_DEBUG +#elif defined(DUK_OPT_NO_DEBUG) +#undef DUK_USE_DEBUG +#else +#undef DUK_USE_DEBUG +#endif + +#if defined(DUK_OPT_DEBUGGER_DUMPHEAP) +#define DUK_USE_DEBUGGER_DUMPHEAP +#elif defined(DUK_OPT_NO_DEBUGGER_DUMPHEAP) +#undef DUK_USE_DEBUGGER_DUMPHEAP +#else +#undef DUK_USE_DEBUGGER_DUMPHEAP +#endif + +#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING) +#define DUK_USE_DEBUGGER_FWD_LOGGING +#elif defined(DUK_OPT_NO_DEBUGGER_FWD_LOGGING) +#undef DUK_USE_DEBUGGER_FWD_LOGGING +#else +#undef DUK_USE_DEBUGGER_FWD_LOGGING +#endif + +#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT) +#define DUK_USE_DEBUGGER_FWD_PRINTALERT +#elif defined(DUK_OPT_NO_DEBUGGER_FWD_PRINTALERT) +#undef DUK_USE_DEBUGGER_FWD_PRINTALERT +#else +#undef DUK_USE_DEBUGGER_FWD_PRINTALERT +#endif + +#if defined(DUK_OPT_DEBUGGER_INSPECT) +#define DUK_USE_DEBUGGER_INSPECT +#elif defined(DUK_OPT_NO_DEBUGGER_INSPECT) +#undef DUK_USE_DEBUGGER_INSPECT +#else +#undef DUK_USE_DEBUGGER_INSPECT +#endif + +#if defined(DUK_OPT_DEBUGGER_PAUSE_UNCAUGHT) +#define DUK_USE_DEBUGGER_PAUSE_UNCAUGHT +#elif defined(DUK_OPT_NO_DEBUGGER_PAUSE_UNCAUGHT) +#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT +#else +#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT +#endif + +#if defined(DUK_OPT_DEBUGGER_SUPPORT) +#define DUK_USE_DEBUGGER_SUPPORT +#elif defined(DUK_OPT_NO_DEBUGGER_SUPPORT) +#undef DUK_USE_DEBUGGER_SUPPORT +#else +#undef DUK_USE_DEBUGGER_SUPPORT +#endif + +#if defined(DUK_OPT_DEBUGGER_THROW_NOTIFY) +#define DUK_USE_DEBUGGER_THROW_NOTIFY +#elif defined(DUK_OPT_NO_DEBUGGER_THROW_NOTIFY) +#undef DUK_USE_DEBUGGER_THROW_NOTIFY +#else +#define DUK_USE_DEBUGGER_THROW_NOTIFY +#endif + +#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE) +#define DUK_USE_DEBUGGER_TRANSPORT_TORTURE +#elif defined(DUK_OPT_NO_DEBUGGER_TRANSPORT_TORTURE) +#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE +#else +#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE +#endif + +#if defined(DUK_OPT_DEBUG_BUFSIZE) +#define DUK_USE_DEBUG_BUFSIZE DUK_OPT_DEBUG_BUFSIZE +#else +#define DUK_USE_DEBUG_BUFSIZE 65536L +#endif + +#if defined(DUK_OPT_REFERENCE_COUNTING) +#define DUK_USE_DOUBLE_LINKED_HEAP +#elif defined(DUK_OPT_NO_REFERENCE_COUNTING) +#undef DUK_USE_DOUBLE_LINKED_HEAP +#else +#define DUK_USE_DOUBLE_LINKED_HEAP +#endif + +#if defined(DUK_OPT_DPRINT) +#define DUK_USE_DPRINT +#elif defined(DUK_OPT_NO_DPRINT) +#undef DUK_USE_DPRINT +#else +#undef DUK_USE_DPRINT +#endif + +#if defined(DUK_OPT_DPRINT_COLORS) +#define DUK_USE_DPRINT_COLORS +#elif defined(DUK_OPT_NO_DPRINT_COLORS) +#undef DUK_USE_DPRINT_COLORS +#else +#undef DUK_USE_DPRINT_COLORS +#endif + +#if defined(DUK_OPT_DPRINT_RDTSC) +#define DUK_USE_DPRINT_RDTSC +#elif defined(DUK_OPT_NO_DPRINT_RDTSC) +#undef DUK_USE_DPRINT_RDTSC +#else +#undef DUK_USE_DPRINT_RDTSC +#endif + +#if defined(DUK_OPT_AUGMENT_ERRORS) +#define DUK_USE_ERRCREATE +#elif defined(DUK_OPT_NO_AUGMENT_ERRORS) +#undef DUK_USE_ERRCREATE +#else +#define DUK_USE_ERRCREATE +#endif + +#if defined(DUK_OPT_AUGMENT_ERRORS) +#define DUK_USE_ERRTHROW +#elif defined(DUK_OPT_NO_AUGMENT_ERRORS) +#undef DUK_USE_ERRTHROW +#else +#define DUK_USE_ERRTHROW +#endif + +#if defined(DUK_OPT_ES6_OBJECT_PROTO_PROPERTY) +#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY +#elif defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY) +#undef DUK_USE_ES6_OBJECT_PROTO_PROPERTY +#else +#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY +#endif + +#if defined(DUK_OPT_ES6_OBJECT_SETPROTOTYPEOF) +#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF +#elif defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF) +#undef DUK_USE_ES6_OBJECT_SETPROTOTYPEOF +#else +#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF +#endif + +#if defined(DUK_OPT_ES6_PROXY) +#define DUK_USE_ES6_PROXY +#elif defined(DUK_OPT_NO_ES6_PROXY) +#undef DUK_USE_ES6_PROXY +#else +#define DUK_USE_ES6_PROXY +#endif + +#if defined(DUK_OPT_ES6_REGEXP_BRACES) +#define DUK_USE_ES6_REGEXP_BRACES +#elif defined(DUK_OPT_NO_ES6_REGEXP_BRACES) +#undef DUK_USE_ES6_REGEXP_BRACES +#else +#define DUK_USE_ES6_REGEXP_BRACES +#endif + +#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK +#if defined(DUK_OPT_DEBUG) || defined(DUK_OPT_ASSERTIONS) +/* Enabled with debug/assertions just so that any issues can be caught. */ +#define DUK_USE_EXEC_INDIRECT_BOUND_CHECK +#endif + +#undef DUK_USE_EXEC_TIMEOUT_CHECK +#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK) +#define DUK_USE_EXEC_TIMEOUT_CHECK(udata) DUK_OPT_EXEC_TIMEOUT_CHECK((udata)) +#endif + +#undef DUK_USE_EXTSTR_FREE +#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_FREE) +#define DUK_USE_EXTSTR_FREE(udata,ptr) DUK_OPT_EXTSTR_FREE((udata), (ptr)) +#endif + +#undef DUK_USE_EXTSTR_INTERN_CHECK +#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_INTERN_CHECK) +#define DUK_USE_EXTSTR_INTERN_CHECK(udata,ptr,len) DUK_OPT_EXTSTR_INTERN_CHECK((udata), (ptr), (len)) +#endif + /* Support for 48-bit signed integer duk_tval with transparent semantics. */ #undef DUK_USE_FASTINT #if defined(DUK_OPT_FASTINT) @@ -2344,665 +3001,452 @@ typedef FILE duk_file; #define DUK_USE_FASTINT #endif -/* - * Memory management options - */ - -#define DUK_USE_REFERENCE_COUNTING -#define DUK_USE_DOUBLE_LINKED_HEAP -#define DUK_USE_MARK_AND_SWEEP -#define DUK_USE_MS_STRINGTABLE_RESIZE - -#if defined(DUK_OPT_NO_REFERENCE_COUNTING) -#undef DUK_USE_REFERENCE_COUNTING -#undef DUK_USE_DOUBLE_LINKED_HEAP -/* XXX: undef DUK_USE_MS_STRINGTABLE_RESIZE as it is more expensive - * with more frequent mark-and-sweeps? - */ +#if defined(DUK_OPT_FILE_IO) +#define DUK_USE_FILE_IO +#elif defined(DUK_OPT_NO_FILE_IO) +#undef DUK_USE_FILE_IO +#else +#define DUK_USE_FILE_IO #endif -#if defined(DUK_OPT_NO_MARK_AND_SWEEP) -#undef DUK_USE_MARK_AND_SWEEP +#if defined(DUK_OPT_FUNCPTR16) +#define DUK_USE_FUNCPTR16 +#elif defined(DUK_OPT_NO_FUNCPTR16) +#undef DUK_USE_FUNCPTR16 +#else +#undef DUK_USE_FUNCPTR16 #endif -#if defined(DUK_USE_MARK_AND_SWEEP) -#define DUK_USE_VOLUNTARY_GC -#if defined(DUK_OPT_NO_VOLUNTARY_GC) -#undef DUK_USE_VOLUNTARY_GC -#endif +#if defined(DUK_OPT_FUNCPTR_DEC16) +#define DUK_USE_FUNCPTR_DEC16(udata,ptr) DUK_OPT_FUNCPTR_DEC16((udata),(ptr)) +#else +#undef DUK_USE_FUNCPTR_DEC16 #endif -#if !defined(DUK_USE_MARK_AND_SWEEP) && !defined(DUK_USE_REFERENCE_COUNTING) -#error must have either mark-and-sweep or reference counting enabled +#if defined(DUK_OPT_FUNCPTR_ENC16) +#define DUK_USE_FUNCPTR_ENC16(udata,ptr) DUK_OPT_FUNCPTR_ENC16((udata),(ptr)) +#else +#undef DUK_USE_FUNCPTR_ENC16 #endif -#if defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE) -#undef DUK_USE_MS_STRINGTABLE_RESIZE -#endif - -#undef DUK_USE_GC_TORTURE #if defined(DUK_OPT_GC_TORTURE) #define DUK_USE_GC_TORTURE -#endif - -/* - * String table options - */ - -#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE) -/* Low memory algorithm: separate chaining using arrays, fixed size hash */ -#define DUK_USE_STRTAB_CHAIN -#define DUK_USE_STRTAB_CHAIN_SIZE DUK_OPT_STRTAB_CHAIN_SIZE +#elif defined(DUK_OPT_NO_GC_TORTURE) +#undef DUK_USE_GC_TORTURE #else -/* Default algorithm: open addressing (probing) */ -#define DUK_USE_STRTAB_PROBE +#undef DUK_USE_GC_TORTURE #endif -/* - * Error handling options - */ - -#define DUK_USE_AUGMENT_ERROR_CREATE -#define DUK_USE_AUGMENT_ERROR_THROW -#define DUK_USE_TRACEBACKS -#define DUK_USE_ERRCREATE -#define DUK_USE_ERRTHROW - -#define DUK_USE_VERBOSE_ERRORS - -#if defined(DUK_OPT_NO_AUGMENT_ERRORS) -#undef DUK_USE_AUGMENT_ERROR_CREATE -#undef DUK_USE_AUGMENT_ERROR_THROW -#undef DUK_USE_TRACEBACKS -#undef DUK_USE_ERRCREATE -#undef DUK_USE_ERRTHROW -#elif defined(DUK_OPT_NO_TRACEBACKS) -#undef DUK_USE_TRACEBACKS -#endif - -#if defined(DUK_OPT_NO_VERBOSE_ERRORS) -#undef DUK_USE_VERBOSE_ERRORS -#endif - -#if defined(DUK_USE_TRACEBACKS) -#if defined(DUK_OPT_TRACEBACK_DEPTH) -#define DUK_USE_TRACEBACK_DEPTH DUK_OPT_TRACEBACK_DEPTH +#if defined(DUK_OPT_HEAPPTR16) +#define DUK_USE_HEAPPTR16 +#elif defined(DUK_OPT_NO_HEAPPTR16) +#undef DUK_USE_HEAPPTR16 #else -#define DUK_USE_TRACEBACK_DEPTH 10 -#endif +#undef DUK_USE_HEAPPTR16 #endif -/* Include messages in executor internal errors. */ -#define DUK_USE_VERBOSE_EXECUTOR_ERRORS +#if defined(DUK_OPT_HEAPPTR_DEC16) +#define DUK_USE_HEAPPTR_DEC16(udata,ptr) DUK_OPT_HEAPPTR_DEC16((udata),(ptr)) +#else +#undef DUK_USE_HEAPPTR_DEC16 +#endif -/* - * Execution and debugger options - */ +#if defined(DUK_OPT_HEAPPTR_ENC16) +#define DUK_USE_HEAPPTR_ENC16(udata,ptr) DUK_OPT_HEAPPTR_ENC16((udata),(ptr)) +#else +#undef DUK_USE_HEAPPTR_ENC16 +#endif + +/* For now, hash part is dropped if and only if 16-bit object fields are used. */ +#define DUK_USE_HOBJECT_HASH_PART +#if defined(DUK_OPT_OBJSIZES16) +#undef DUK_USE_HOBJECT_HASH_PART +#endif + +#if defined(DUK_OPT_HSTRING_CLEN) +#define DUK_USE_HSTRING_CLEN +#elif defined(DUK_OPT_NO_HSTRING_CLEN) +#undef DUK_USE_HSTRING_CLEN +#else +#define DUK_USE_HSTRING_CLEN +#endif + +#if defined(DUK_OPT_EXTERNAL_STRINGS) +#define DUK_USE_HSTRING_EXTDATA +#elif defined(DUK_OPT_NO_EXTERNAL_STRINGS) +#undef DUK_USE_HSTRING_EXTDATA +#else +#undef DUK_USE_HSTRING_EXTDATA +#endif -#undef DUK_USE_INTERRUPT_COUNTER #if defined(DUK_OPT_INTERRUPT_COUNTER) #define DUK_USE_INTERRUPT_COUNTER -#endif - -#undef DUK_USE_EXEC_TIMEOUT_CHECK -#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK) -#define DUK_USE_EXEC_TIMEOUT_CHECK(udata) DUK_OPT_EXEC_TIMEOUT_CHECK((udata)) -#endif - -#undef DUK_USE_DEBUGGER_SUPPORT -#if defined(DUK_OPT_DEBUGGER_SUPPORT) -#define DUK_USE_DEBUGGER_SUPPORT -#endif - -#undef DUK_USE_DEBUGGER_FWD_PRINTALERT -#if defined(DUK_OPT_DEBUGGER_SUPPORT) && defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT) -#define DUK_USE_DEBUGGER_FWD_PRINTALERT -#endif - -#undef DUK_USE_DEBUGGER_FWD_LOGGING -#if defined(DUK_OPT_DEBUGGER_SUPPORT) && defined(DUK_OPT_DEBUGGER_FWD_LOGGING) -#define DUK_USE_DEBUGGER_FWD_LOGGING -#endif - -/* DumpHeap is optional because it's not always needed and has a relatively - * large footprint. - */ -#undef DUK_USE_DEBUGGER_DUMPHEAP -#if defined(DUK_OPT_DEBUGGER_DUMPHEAP) -#define DUK_USE_DEBUGGER_DUMPHEAP -#endif - -/* Debugger transport read/write torture. */ -#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE -#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE) -#define DUK_USE_DEBUGGER_TRANSPORT_TORTURE -#endif - -/* For opcodes with indirect indices, check final index against stack size. - * This should not be necessary because the compiler is trusted, and we don't - * bound check non-indirect indices either. - */ -#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK -#if defined(DUK_OPT_DEBUG) || defined(DUK_OPT_ASSERTIONS) -/* Enabled with debug/assertions just so that any issues can be caught. */ -#define DUK_USE_EXEC_INDIRECT_BOUND_CHECK -#endif - -/* - * Debug printing and assertion options - */ - -#undef DUK_USE_DEBUG -#undef DUK_USE_DPRINT -#undef DUK_USE_DDPRINT -#undef DUK_USE_DDDPRINT -#undef DUK_USE_DPRINT_RDTSC -#undef DUK_USE_ASSERTIONS - -/* Global debug enable. Compile must be clean on C99 regardless of whether or - * not debugging is enabled. On non-C99 platforms compile should be clean with - * debugging disabled but may produce warnings with debugging enabled (related - * to debug macro hackery and such). - */ -#if defined(DUK_OPT_DEBUG) -#define DUK_USE_DEBUG -#endif - -#if defined(DUK_OPT_DEBUG) && defined(DUK_OPT_DPRINT) -#define DUK_USE_DPRINT -#endif -#if defined(DUK_OPT_DEBUG) && defined(DUK_OPT_DDPRINT) -#define DUK_USE_DDPRINT -#endif -#if defined(DUK_OPT_DEBUG) && defined(DUK_OPT_DDDPRINT) -#define DUK_USE_DDDPRINT -#endif - -#undef DUK_USE_DPRINT_COLORS -#if defined(DUK_OPT_DPRINT_COLORS) -#define DUK_USE_DPRINT_COLORS -#endif - -#if defined(DUK_USE_RDTSC) && defined(DUK_OPT_DPRINT_RDTSC) -#define DUK_USE_DPRINT_RDTSC +#elif defined(DUK_OPT_NO_INTERRUPT_COUNTER) +#undef DUK_USE_INTERRUPT_COUNTER #else -#undef DUK_USE_DPRINT_RDTSC +#undef DUK_USE_INTERRUPT_COUNTER #endif -#if defined(DUK_OPT_ASSERTIONS) -#define DUK_USE_ASSERTIONS -#endif - -/* The static buffer for debug printing is quite large by default, so there - * is an option to shrink it manually for constrained builds. - */ -#if defined(DUK_OPT_DEBUG_BUFSIZE) -#define DUK_USE_DEBUG_BUFSIZE DUK_OPT_DEBUG_BUFSIZE +#if defined(DUK_OPT_JC) +#define DUK_USE_JC +#elif defined(DUK_OPT_NO_JC) +#undef DUK_USE_JC #else -#define DUK_USE_DEBUG_BUFSIZE 65536L +#define DUK_USE_JC #endif -/* - * Ecmascript features / compliance options - */ - -#if defined(DUK_F_BCC) -/* Math built-in is stubbed out on BCC to allow compiler torture testing. */ +#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH) +#define DUK_USE_JSON_STRINGIFY_FASTPATH +#elif defined(DUK_OPT_NO_JSON_STRINGIFY_FASTPATH) +#undef DUK_USE_JSON_STRINGIFY_FASTPATH #else -#define DUK_USE_MATH_BUILTIN +#undef DUK_USE_JSON_STRINGIFY_FASTPATH #endif -#define DUK_USE_STRICT_DECL -#if defined(DUK_OPT_NO_STRICT_DECL) -#undef DUK_USE_STRICT_DECL +#if defined(DUK_OPT_JX) +#define DUK_USE_JX +#elif defined(DUK_OPT_NO_JX) +#undef DUK_USE_JX +#else +#define DUK_USE_JX #endif -#define DUK_USE_REGEXP_SUPPORT -#if defined(DUK_OPT_NO_REGEXP_SUPPORT) -#undef DUK_USE_REGEXP_SUPPORT +#if defined(DUK_OPT_LIGHTFUNC_BUILTINS) +#define DUK_USE_LIGHTFUNC_BUILTINS +#elif defined(DUK_OPT_NO_LIGHTFUNC_BUILTINS) +#undef DUK_USE_LIGHTFUNC_BUILTINS +#else +#undef DUK_USE_LIGHTFUNC_BUILTINS #endif -#undef DUK_USE_STRICT_UTF8_SOURCE -#if defined(DUK_OPT_STRICT_UTF8_SOURCE) -#define DUK_USE_STRICT_UTF8_SOURCE +#if defined(DUK_OPT_MARK_AND_SWEEP) +#define DUK_USE_MARK_AND_SWEEP +#elif defined(DUK_OPT_NO_MARK_AND_SWEEP) +#undef DUK_USE_MARK_AND_SWEEP +#else +#define DUK_USE_MARK_AND_SWEEP #endif -#define DUK_USE_OCTAL_SUPPORT -#if defined(DUK_OPT_NO_OCTAL_SUPPORT) -#undef DUK_USE_OCTAL_SUPPORT +#if defined(DUK_OPT_MS_STRINGTABLE_RESIZE) +#define DUK_USE_MS_STRINGTABLE_RESIZE +#elif defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE) +#undef DUK_USE_MS_STRINGTABLE_RESIZE +#else +#define DUK_USE_MS_STRINGTABLE_RESIZE #endif -#define DUK_USE_SOURCE_NONBMP -#if defined(DUK_OPT_NO_SOURCE_NONBMP) -#undef DUK_USE_SOURCE_NONBMP -#endif - -#define DUK_USE_BROWSER_LIKE -#if defined(DUK_OPT_NO_BROWSER_LIKE) -#undef DUK_USE_BROWSER_LIKE -#endif - -/* E5/E5.1 Section B features. */ -#define DUK_USE_SECTION_B -#if defined(DUK_OPT_NO_SECTION_B) -#undef DUK_USE_SECTION_B -#endif - -/* Non-standard regexp parsing features. */ -#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE - -/* Treat function statements (function declarations outside top level of - * Program or FunctionBody) same as normal function declarations. This is - * also V8 behavior. See test-dev-func-decl-outside-top.js. - */ -#define DUK_USE_NONSTD_FUNC_STMT -#if defined(DUK_OPT_NO_NONSTD_FUNC_STMT) -#undef DUK_USE_NONSTD_FUNC_STMT -#endif - -/* Array.prototype.splice() non-standard but real world compatible behavior - * when deleteCount is omitted. - */ -#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT -#if defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT) -#undef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT -#endif - -/* Array.prototype.concat() non-standard but real world compatible behavior - * for non-existent trailing elements. - */ +#if defined(DUK_OPT_NONSTD_ARRAY_CONCAT_TRAILER) #define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER -#if defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER) +#elif defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER) #undef DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER +#else +#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER #endif -/* Array.prototype.map() non-standard but real world compatible behavior - * for non-existent trailing elements. - */ +#if defined(DUK_OPT_NONSTD_ARRAY_MAP_TRAILER) #define DUK_USE_NONSTD_ARRAY_MAP_TRAILER -#if defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER) +#elif defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER) #undef DUK_USE_NONSTD_ARRAY_MAP_TRAILER +#else +#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER +#endif + +#if defined(DUK_OPT_NONSTD_ARRAY_SPLICE_DELCOUNT) +#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT +#elif defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT) +#undef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT +#else +#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT #endif -/* Non-standard 'caller' property for function instances, see - * test-bi-function-nonstd-caller-prop.js. - */ -#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY #if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) #define DUK_USE_NONSTD_FUNC_CALLER_PROPERTY +#elif defined(DUK_OPT_NO_NONSTD_FUNC_CALLER_PROPERTY) +#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY +#else +#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY #endif -/* Non-standard Object.prototype.__proto__ (ES6), see - * test-bi-object-proto-__proto__.js. - */ -#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY -#if defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY) -#undef DUK_USE_ES6_OBJECT_PROTO_PROPERTY -#endif - -/* Non-standard Object.setPrototypeOf (ES6), see - * test-bi-object-setprototypeof.js. - */ -#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF -#if defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF) -#undef DUK_USE_ES6_OBJECT_SETPROTOTYPEOF -#endif - -/* ES6 Proxy object (subset for now). */ -#define DUK_USE_ES6_PROXY -#if defined(DUK_OPT_NO_ES6_PROXY) -#undef DUK_USE_ES6_PROXY -#endif - -/* Record pc-to-line information. */ -#define DUK_USE_PC2LINE -#if defined(DUK_OPT_NO_PC2LINE) -#undef DUK_USE_PC2LINE -#endif - -/* Non-standard function 'source' property. */ -#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY #if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY) #define DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY +#elif defined(DUK_OPT_NO_NONSTD_FUNC_SOURCE_PROPERTY) +#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY +#else +#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY #endif -/* CommonJS modules */ -#define DUK_USE_COMMONJS_MODULES -#if defined(DUK_OPT_NO_COMMONJS_MODULES) -#undef DUK_USE_COMMONJS_MODULES +#if defined(DUK_OPT_NONSTD_FUNC_STMT) +#define DUK_USE_NONSTD_FUNC_STMT +#elif defined(DUK_OPT_NO_NONSTD_FUNC_STMT) +#undef DUK_USE_NONSTD_FUNC_STMT +#else +#define DUK_USE_NONSTD_FUNC_STMT #endif -/* Additional key argument to setter/getter calls when triggered by property - * accesses. - */ - +#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT) #define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT -#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT -#if defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) +#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) #undef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT -#undef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT +#else +#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT #endif -/* JSON escaping of U+2028 and U+2029. - */ - +#if defined(DUK_OPT_NONSTD_JSON_ESC_U2028_U2029) #define DUK_USE_NONSTD_JSON_ESC_U2028_U2029 -#if defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029) +#elif defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029) #undef DUK_USE_NONSTD_JSON_ESC_U2028_U2029 +#else +#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029 #endif -/* Allow 32-bit codepoints in String.fromCharCode. */ +#if defined(DUK_OPT_NONSTD_REGEXP_DOLLAR_ESCAPE) +#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE +#elif defined(DUK_OPT_NO_NONSTD_REGEXP_DOLLAR_ESCAPE) +#undef DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE +#else +#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE +#endif + +#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT) +#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT +#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) +#undef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT +#else +#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT +#endif + +#if defined(DUK_OPT_NONSTD_STRING_FROMCHARCODE_32BIT) #define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT -#if defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT) +#elif defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT) #undef DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT +#else +#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT #endif -/* Non-standard array fast path write behavior: when writing to numeric - * indexes of an Array instance, assume Array.prototype doesn't have - * conflicting properties (e.g. a non-writable property "7"). - */ -#define DUK_USE_NONSTD_ARRAY_WRITE -#if defined(DUK_OPT_NO_NONSTD_ARRAY_WRITE) -#undef DUK_USE_NONSTD_ARRAY_WRITE +#if defined(DUK_OPT_OBJSIZES16) +#define DUK_USE_OBJSIZES16 +#elif defined(DUK_OPT_NO_OBJSIZES16) +#undef DUK_USE_OBJSIZES16 +#else +#undef DUK_USE_OBJSIZES16 #endif -/* Node.js Buffer and Khronos/ES6 typed array support. */ -#define DUK_USE_BUFFEROBJECT_SUPPORT -#if defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT) -#undef DUK_USE_BUFFEROBJECT_SUPPORT +#if defined(DUK_OPT_OCTAL_SUPPORT) +#define DUK_USE_OCTAL_SUPPORT +#elif defined(DUK_OPT_NO_OCTAL_SUPPORT) +#undef DUK_USE_OCTAL_SUPPORT +#else +#define DUK_USE_OCTAL_SUPPORT #endif -/* - * Optional C API options - */ - -#define DUK_USE_BYTECODE_DUMP_SUPPORT -#if defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT) -#undef DUK_USE_BYTECODE_DUMP_SUPPORT +#if defined(DUK_OPT_PACKED_TVAL) +#define DUK_USE_PACKED_TVAL +#elif defined(DUK_OPT_NO_PACKED_TVAL) +#undef DUK_USE_PACKED_TVAL +#else +/* Already provided above */ #endif -/* - * Tailcalls - */ - -/* Tailcalls are enabled by default. The non-standard function 'caller' - * property feature conflicts with tailcalls quite severely so tailcalls - * are disabled if the 'caller' property is enabled. - */ -#define DUK_USE_TAILCALL -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) -#undef DUK_USE_TAILCALL +#undef DUK_USE_PANIC_ABORT +#if !defined(DUK_OPT_SEGFAULT_ON_PANIC) +#define DUK_USE_PANIC_ABORT #endif -/* - * Ecmascript compiler - */ - -/* Ensure final bytecode never exceeds a certain byte size and never uses - * line numbers above a certain limit. This ensures that there is no need - * to deal with unbounded ranges in e.g. pc2line data structures. For now, - * limits are set so that signed 32-bit values can represent line number - * and byte offset with room to spare. - */ -#define DUK_USE_ESBC_LIMITS -#define DUK_USE_ESBC_MAX_LINENUMBER 0x7fff0000L -#define DUK_USE_ESBC_MAX_BYTES 0x7fff0000L - -#undef DUK_USE_SHUFFLE_TORTURE -#if defined(DUK_OPT_SHUFFLE_TORTURE) -#define DUK_USE_SHUFFLE_TORTURE -#endif - -/* - * User panic handler, panic exit behavior for default panic handler - */ - #undef DUK_USE_PANIC_HANDLER #if defined(DUK_OPT_PANIC_HANDLER) #define DUK_USE_PANIC_HANDLER(code,msg) DUK_OPT_PANIC_HANDLER((code),(msg)) #endif -#undef DUK_USE_PANIC_ABORT -#undef DUK_USE_PANIC_EXIT #undef DUK_USE_PANIC_SEGFAULT - #if defined(DUK_OPT_SEGFAULT_ON_PANIC) #define DUK_USE_PANIC_SEGFAULT +#endif + +#if defined(DUK_OPT_PARANOID_ERRORS) +#define DUK_USE_PARANOID_ERRORS +#elif defined(DUK_OPT_NO_PARANOID_ERRORS) +#undef DUK_USE_PARANOID_ERRORS #else -#define DUK_USE_PANIC_ABORT +#undef DUK_USE_PARANOID_ERRORS #endif -/* - * File I/O support. This is now used in a few API calls to e.g. push - * a string from file contents or eval a file. For portability it must - * be possible to disable I/O altogether. - */ - -#undef DUK_USE_FILE_IO -#if !defined(DUK_OPT_NO_FILE_IO) -#define DUK_USE_FILE_IO +#if defined(DUK_OPT_PC2LINE) +#define DUK_USE_PC2LINE +#elif defined(DUK_OPT_NO_PC2LINE) +#undef DUK_USE_PC2LINE +#else +#define DUK_USE_PC2LINE #endif -/* - * Optional run-time self tests executed when a heap is created. Some - * platform/compiler issues cannot be determined at compile time. One - * particular example is the bug described in misc/clang_aliasing.c. - */ - -#undef DUK_USE_SELF_TESTS -#if defined(DUK_OPT_SELF_TESTS) -#define DUK_USE_SELF_TESTS -#endif - -/* Double aliasing testcase fails when Emscripten-generated code is run - * on Firefox. This is not fatal because it only affects packed duk_tval - * which we avoid with Emscripten. - */ -#undef DUK_USE_NO_DOUBLE_ALIASING_SELFTEST -#if defined(DUK_F_EMSCRIPTEN) -#define DUK_USE_NO_DOUBLE_ALIASING_SELFTEST -#endif - -/* - * Codecs - */ - -#define DUK_USE_JX -#if defined(DUK_OPT_NO_JX) -#undef DUK_USE_JX -#endif - -#define DUK_USE_JC -#if defined(DUK_OPT_NO_JC) -#undef DUK_USE_JC -#endif - -/* - * InitJS code - */ - -/* Always use the built-in InitJS code for now. */ -#define DUK_USE_BUILTIN_INITJS - -/* User provided InitJS. */ -#undef DUK_USE_USER_INITJS -#if defined(DUK_OPT_USER_INITJS) -#define DUK_USE_USER_INITJS (DUK_OPT_USER_INITJS) -#endif - -/* - * External string data support - * - * Allow duk_hstrings to store data also behind an external pointer (see - * duk_hstring_external). This increases code size slightly but is useful - * in low memory environments where memory is more limited than flash. - */ - -#undef DUK_USE_HSTRING_EXTDATA -#if defined(DUK_OPT_EXTERNAL_STRINGS) -#define DUK_USE_HSTRING_EXTDATA -#endif - -#undef DUK_USE_EXTSTR_INTERN_CHECK -#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_INTERN_CHECK) -#define DUK_USE_EXTSTR_INTERN_CHECK(udata,ptr,len) DUK_OPT_EXTSTR_INTERN_CHECK((udata), (ptr), (len)) -#endif - -#undef DUK_USE_EXTSTR_FREE -#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_FREE) -#define DUK_USE_EXTSTR_FREE(udata,ptr) DUK_OPT_EXTSTR_FREE((udata), (ptr)) -#endif - -/* - * Lightweight functions - */ - -/* Force built-ins to use lightfunc function pointers when possible. This - * makes the built-in functions non-compliant with respect to their property - * values and such, but is very useful in low memory environments (can save - * around 14kB of initial RAM footprint). - */ -#undef DUK_USE_LIGHTFUNC_BUILTINS -#if defined(DUK_OPT_LIGHTFUNC_BUILTINS) -#define DUK_USE_LIGHTFUNC_BUILTINS -#endif - -/* - * Pointer compression and 16-bit header fields for low memory environments - */ - -#undef DUK_USE_HEAPPTR16 -#undef DUK_USE_HEAPPTR_ENC16 -#undef DUK_USE_HEAPPTR_DEC16 -#if defined(DUK_OPT_HEAPPTR16) && defined(DUK_OPT_HEAPPTR_ENC16) && defined(DUK_OPT_HEAPPTR_DEC16) -#define DUK_USE_HEAPPTR16 -#define DUK_USE_HEAPPTR_ENC16(udata,ptr) DUK_OPT_HEAPPTR_ENC16((udata),(ptr)) -#define DUK_USE_HEAPPTR_DEC16(udata,ptr) DUK_OPT_HEAPPTR_DEC16((udata),(ptr)) -#endif - -#undef DUK_USE_DATAPTR16 -#undef DUK_USE_DATAPTR_ENC16 -#undef DUK_USE_DATAPTR_DEC16 -#if defined(DUK_OPT_DATAPTR16) && defined(DUK_OPT_DATAPTR_ENC16) && defined(DUK_OPT_DATAPTR_DEC16) -#define DUK_USE_DATAPTR16 -#define DUK_USE_DATAPTR_ENC16(udata,ptr) DUK_OPT_DATAPTR_ENC16((udata),(ptr)) -#define DUK_USE_DATAPTR_DEC16(udata,ptr) DUK_OPT_DATAPTR_DEC16((udata),(ptr)) -#endif - -#undef DUK_USE_FUNCPTR16 -#undef DUK_USE_FUNCPTR_ENC16 -#undef DUK_USE_FUNCPTR_DEC16 -#if defined(DUK_OPT_FUNCPTR16) && defined(DUK_OPT_FUNCPTR_ENC16) && defined(DUK_OPT_FUNCPTR_DEC16) -#define DUK_USE_FUNCPTR16 -#define DUK_USE_FUNCPTR_ENC16(udata,ptr) DUK_OPT_FUNCPTR_ENC16((udata),(ptr)) -#define DUK_USE_FUNCPTR_DEC16(udata,ptr) DUK_OPT_FUNCPTR_DEC16((udata),(ptr)) -#endif - -#undef DUK_USE_REFCOUNT16 #if defined(DUK_OPT_REFCOUNT16) #define DUK_USE_REFCOUNT16 +#elif defined(DUK_OPT_NO_REFCOUNT16) +#undef DUK_USE_REFCOUNT16 +#else +#undef DUK_USE_REFCOUNT16 +#endif + +#if defined(DUK_OPT_REFERENCE_COUNTING) +#define DUK_USE_REFERENCE_COUNTING +#elif defined(DUK_OPT_NO_REFERENCE_COUNTING) +#undef DUK_USE_REFERENCE_COUNTING +#else +#define DUK_USE_REFERENCE_COUNTING +#endif + +#if defined(DUK_OPT_REGEXP_CANON_WORKAROUND) +#define DUK_USE_REGEXP_CANON_WORKAROUND +#elif defined(DUK_OPT_NO_REGEXP_CANON_WORKAROUND) +#undef DUK_USE_REGEXP_CANON_WORKAROUND +#else +#undef DUK_USE_REGEXP_CANON_WORKAROUND +#endif + +#if defined(DUK_OPT_REGEXP_SUPPORT) +#define DUK_USE_REGEXP_SUPPORT +#elif defined(DUK_OPT_NO_REGEXP_SUPPORT) +#undef DUK_USE_REGEXP_SUPPORT +#else +#define DUK_USE_REGEXP_SUPPORT +#endif + +#if defined(DUK_OPT_ROM_GLOBAL_CLONE) +#define DUK_USE_ROM_GLOBAL_CLONE +#elif defined(DUK_OPT_NO_ROM_GLOBAL_CLONE) +#undef DUK_USE_ROM_GLOBAL_CLONE +#else +#undef DUK_USE_ROM_GLOBAL_CLONE +#endif + +#if defined(DUK_OPT_ROM_GLOBAL_INHERIT) +#define DUK_USE_ROM_GLOBAL_INHERIT +#elif defined(DUK_OPT_NO_ROM_GLOBAL_INHERIT) +#undef DUK_USE_ROM_GLOBAL_INHERIT +#else +#undef DUK_USE_ROM_GLOBAL_INHERIT +#endif + +#if defined(DUK_OPT_ROM_OBJECTS) +#define DUK_USE_ROM_OBJECTS +#elif defined(DUK_OPT_NO_ROM_OBJECTS) +#undef DUK_USE_ROM_OBJECTS +#else +#undef DUK_USE_ROM_OBJECTS +#endif + +#if defined(DUK_OPT_ROM_STRINGS) +#define DUK_USE_ROM_STRINGS +#elif defined(DUK_OPT_NO_ROM_STRINGS) +#undef DUK_USE_ROM_STRINGS +#else +#undef DUK_USE_ROM_STRINGS +#endif + +#if defined(DUK_OPT_SECTION_B) +#define DUK_USE_SECTION_B +#elif defined(DUK_OPT_NO_SECTION_B) +#undef DUK_USE_SECTION_B +#else +#define DUK_USE_SECTION_B +#endif + +#if defined(DUK_OPT_SELF_TESTS) +#define DUK_USE_SELF_TESTS +#elif defined(DUK_OPT_NO_SELF_TESTS) +#undef DUK_USE_SELF_TESTS +#else +#undef DUK_USE_SELF_TESTS +#endif + +#if defined(DUK_OPT_SHUFFLE_TORTURE) +#define DUK_USE_SHUFFLE_TORTURE +#elif defined(DUK_OPT_NO_SHUFFLE_TORTURE) +#undef DUK_USE_SHUFFLE_TORTURE +#else +#undef DUK_USE_SHUFFLE_TORTURE +#endif + +#if defined(DUK_OPT_SOURCE_NONBMP) +#define DUK_USE_SOURCE_NONBMP +#elif defined(DUK_OPT_NO_SOURCE_NONBMP) +#undef DUK_USE_SOURCE_NONBMP +#else +#define DUK_USE_SOURCE_NONBMP #endif -#undef DUK_USE_STRHASH16 #if defined(DUK_OPT_STRHASH16) #define DUK_USE_STRHASH16 +#elif defined(DUK_OPT_NO_STRHASH16) +#undef DUK_USE_STRHASH16 +#else +#undef DUK_USE_STRHASH16 +#endif + +#if defined(DUK_OPT_STRICT_DECL) +#define DUK_USE_STRICT_DECL +#elif defined(DUK_OPT_NO_STRICT_DECL) +#undef DUK_USE_STRICT_DECL +#else +#define DUK_USE_STRICT_DECL +#endif + +#if defined(DUK_OPT_STRICT_UTF8_SOURCE) +#define DUK_USE_STRICT_UTF8_SOURCE +#elif defined(DUK_OPT_NO_STRICT_UTF8_SOURCE) +#undef DUK_USE_STRICT_UTF8_SOURCE +#else +#undef DUK_USE_STRICT_UTF8_SOURCE #endif -#undef DUK_USE_STRLEN16 #if defined(DUK_OPT_STRLEN16) #define DUK_USE_STRLEN16 -#endif - -#undef DUK_USE_BUFLEN16 -#if defined(DUK_OPT_BUFLEN16) -#define DUK_USE_BUFLEN16 -#endif - -#undef DUK_USE_OBJSIZES16 -#if defined(DUK_OPT_OBJSIZES16) -#define DUK_USE_OBJSIZES16 -#endif - -/* For now, hash part is dropped if and only if 16-bit object fields are used. */ -#define DUK_USE_HOBJECT_HASH_PART -#if defined(DUK_USE_OBJSIZES16) -#undef DUK_USE_HOBJECT_HASH_PART -#endif - -/* - * Miscellaneous - */ - -/* Convenience define: 32-bit pointers. 32-bit platforms are an important - * footprint optimization target, and this define allows e.g. struct sizes - * to be organized for compactness. - */ -#undef DUK_USE_32BIT_PTRS -#if defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) -#if DUK_UINTPTR_MAX <= 0xffffffffUL -#define DUK_USE_32BIT_PTRS -#endif -#endif - -#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS -#undef DUK_USE_EXPLICIT_NULL_INIT - -#define DUK_USE_ZERO_BUFFER_DATA -#if defined(DUK_OPT_NO_ZERO_BUFFER_DATA) -#undef DUK_USE_ZERO_BUFFER_DATA -#endif - -#undef DUK_USE_VARIADIC_MACROS -#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__)) -#define DUK_USE_VARIADIC_MACROS -#endif -#if defined(_MSC_VER) && !defined(DUK_USE_VARIADIC_MACROS) -#if (_MSC_VER >= 1400) -/* VS2005+ should have variadic macros even when they're not C99. */ -#define DUK_USE_VARIADIC_MACROS -#endif -#endif - -/* - * Variable size array initialization. - * - * Variable size array at the end of a structure is nonportable. - * There are three alternatives: - * - * 1) C99 (flexible array member): char buf[] - * 2) Compiler specific (e.g. GCC): char buf[0] - * 3) Portable but wastes memory / complicates allocation: char buf[1] - */ - -/* XXX: Currently unused, only hbuffer.h needed this at some point. */ -#undef DUK_USE_FLEX_C99 -#undef DUK_USE_FLEX_ZEROSIZE -#undef DUK_USE_FLEX_ONESIZE -#if defined(DUK_F_C99) -#define DUK_USE_FLEX_C99 -#elif defined(__GNUC__) -#define DUK_USE_FLEX_ZEROSIZE +#elif defined(DUK_OPT_NO_STRLEN16) +#undef DUK_USE_STRLEN16 #else -#define DUK_USE_FLEX_ONESIZE +#undef DUK_USE_STRLEN16 #endif -/* - * GCC pragmas - */ +#undef DUK_USE_STRTAB_CHAIN +#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE) +#define DUK_USE_STRTAB_CHAIN +#endif -/* XXX: GCC pragma inside a function fails in some earlier GCC versions (e.g. gcc 4.5). - * This is very approximate but allows clean builds for development right now. - */ -/* http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html */ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6) -#define DUK_USE_GCC_PRAGMAS +#undef DUK_USE_STRTAB_CHAIN_SIZE +#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE) +/* Low memory algorithm: separate chaining using arrays, fixed size hash */ +#define DUK_USE_STRTAB_CHAIN_SIZE DUK_OPT_STRTAB_CHAIN_SIZE +#endif + +#undef DUK_USE_STRTAB_PROBE +#if !(defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE)) +#define DUK_USE_STRTAB_PROBE +#endif + +#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) +#undef DUK_USE_TAILCALL #else -#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_TAILCALL #endif -/* - * User declarations - */ +#if defined(DUK_OPT_TARGET_INFO) +#define DUK_USE_TARGET_INFO DUK_OPT_TARGET_INFO +#else +#define DUK_USE_TARGET_INFO "unknown" +#endif + +#if defined(DUK_OPT_NO_AUGMENT_ERRORS) +#undef DUK_USE_TRACEBACKS +#elif defined(DUK_OPT_NO_TRACEBACKS) +#undef DUK_USE_TRACEBACKS +#else +#define DUK_USE_TRACEBACKS +#endif + +#if defined(DUK_OPT_TRACEBACK_DEPTH) +#define DUK_USE_TRACEBACK_DEPTH DUK_OPT_TRACEBACK_DEPTH +#else +#define DUK_USE_TRACEBACK_DEPTH 10 +#endif #if defined(DUK_OPT_DECLARE) #define DUK_USE_USER_DECLARE() DUK_OPT_DECLARE @@ -3010,29 +3454,80 @@ typedef FILE duk_file; #define DUK_USE_USER_DECLARE() /* no user declarations */ #endif +/* User provided InitJS. */ +#undef DUK_USE_USER_INITJS +#if defined(DUK_OPT_USER_INITJS) +#define DUK_USE_USER_INITJS (DUK_OPT_USER_INITJS) +#endif + +#if defined(DUK_OPT_VERBOSE_ERRORS) +#define DUK_USE_VERBOSE_ERRORS +#elif defined(DUK_OPT_NO_VERBOSE_ERRORS) +#undef DUK_USE_VERBOSE_ERRORS +#else +#define DUK_USE_VERBOSE_ERRORS +#endif + +#if defined(DUK_OPT_VOLUNTARY_GC) +#define DUK_USE_VOLUNTARY_GC +#elif defined(DUK_OPT_NO_VOLUNTARY_GC) +#undef DUK_USE_VOLUNTARY_GC +#else +#define DUK_USE_VOLUNTARY_GC +#endif + +#if defined(DUK_OPT_ZERO_BUFFER_DATA) +#define DUK_USE_ZERO_BUFFER_DATA +#elif defined(DUK_OPT_NO_ZERO_BUFFER_DATA) +#undef DUK_USE_ZERO_BUFFER_DATA +#else +#define DUK_USE_ZERO_BUFFER_DATA +#endif + /* * Autogenerated defaults */ +#define DUK_USE_AVOID_PLATFORM_FUNCPTRS +#define DUK_USE_BASE64_FASTPATH +#define DUK_USE_BUILTIN_INITJS #define DUK_USE_COMPILER_RECLIMIT 2500 #undef DUK_USE_DATE_FORMAT_STRING #undef DUK_USE_DATE_GET_LOCAL_TZOFFSET #undef DUK_USE_DATE_GET_NOW #undef DUK_USE_DATE_PARSE_STRING #undef DUK_USE_DATE_PRS_GETDATE -#undef DUK_USE_INTEGER_ME +#define DUK_USE_ESBC_LIMITS +#define DUK_USE_ESBC_MAX_BYTES 2147418112L +#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L +#undef DUK_USE_EXEC_FUN_LOCAL +#undef DUK_USE_EXPLICIT_NULL_INIT +#define DUK_USE_FAST_REFCOUNT_DEFAULT +#define DUK_USE_HEX_FASTPATH +#define DUK_USE_IDCHAR_FASTPATH +#undef DUK_USE_INTERRUPT_DEBUG_FIXUP #define DUK_USE_JSON_DECNUMBER_FASTPATH #define DUK_USE_JSON_DECSTRING_FASTPATH #define DUK_USE_JSON_DEC_RECLIMIT 1000 #define DUK_USE_JSON_EATWHITE_FASTPATH #define DUK_USE_JSON_ENC_RECLIMIT 1000 #define DUK_USE_JSON_QUOTESTRING_FASTPATH +#define DUK_USE_LEXER_SLIDING_WINDOW #undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE #define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 +#define DUK_USE_MATH_BUILTIN #define DUK_USE_NATIVE_CALL_RECLIMIT 1000 +#undef DUK_USE_PANIC_EXIT +#undef DUK_USE_PREFER_SIZE +#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS #undef DUK_USE_REFZERO_FINALIZER_TORTURE #define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 #define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 +#define DUK_USE_ROM_PTRCOMP_FIRST 63488L +#undef DUK_USE_STRHASH_DENSE +#define DUK_USE_STRHASH_SKIP_SHIFT 5 +#undef DUK_USE_VALSTACK_UNSAFE +#define DUK_USE_VERBOSE_EXECUTOR_ERRORS /* * Alternative customization header @@ -3067,13 +3562,10 @@ typedef FILE duk_file; #if defined(DUK_USE_DATE_GET_NOW) /* External provider already defined. */ #elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx); #define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday((ctx)) #elif defined(DUK_USE_DATE_NOW_TIME) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx); #define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time((ctx)) #elif defined(DUK_USE_DATE_NOW_WINDOWS) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx); #define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows((ctx)) #else #error no provider for DUK_USE_DATE_GET_NOW() @@ -3082,10 +3574,8 @@ DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx); #if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) /* External provider already defined. */ #elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) -DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d); #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) #elif defined(DUK_USE_DATE_TZO_WINDOWS) -DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d); #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) #else #error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() @@ -3094,10 +3584,8 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t #if defined(DUK_USE_DATE_PARSE_STRING) /* External provider already defined. */ #elif defined(DUK_USE_DATE_PRS_STRPTIME) -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str); #define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_strptime((ctx), (str)) #elif defined(DUK_USE_DATE_PRS_GETDATE) -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str); #define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_getdate((ctx), (str)) #else /* No provider for DUK_USE_DATE_PARSE_STRING(), fall back to ISO 8601 only. */ @@ -3106,7 +3594,6 @@ DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, #if defined(DUK_USE_DATE_FORMAT_STRING) /* External provider already defined. */ #elif defined(DUK_USE_DATE_FMT_STRFTIME) -DUK_INTERNAL_DECL 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); #define DUK_USE_DATE_FORMAT_STRING(ctx,parts,tzoffset,flags) \ duk_bi_date_format_parts_strftime((ctx), (parts), (tzoffset), (flags)) #else @@ -3116,109 +3603,202 @@ DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, #endif /* DUK_COMPILING_DUKTAPE */ /* - * Sanity check for the final effective internal defines. Also - * double checks user tweaks made by an optional duk_custom.h header. + * Checks for config option consistency (DUK_USE_xxx) */ -/* - * Deprecated feature options. - * - * Catch so that user more easily notices and updates build. - */ - -#if defined(DUK_OPT_NO_FUNC_STMT) -#error DUK_OPT_NO_FUNC_STMT is deprecated, use DUK_OPT_NO_NONSTD_FUNC_STMT +#if defined(DUK_USE_32BIT_PTRS) +#error unsupported config option used (option has been removed): DUK_USE_32BIT_PTRS #endif - -#if defined(DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY) -#error DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY is deprecated, use DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY +#if defined(DUK_USE_ALIGN_4) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_4 #endif - -#if defined(DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY) -#error DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY is deprecated, use DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY +#if defined(DUK_USE_ALIGN_8) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8 #endif - -#if defined(DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT) -#error DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT is deprecated, use DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT +#if defined(DUK_USE_BYTEORDER_FORCED) +#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED #endif - -#if defined(DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY) -#error DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY is deprecated, use DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY +#if defined(DUK_USE_DATAPTR_DEC16) && !defined(DUK_USE_DATAPTR16) +#error config option DUK_USE_DATAPTR_DEC16 requires option DUK_USE_DATAPTR16 (which is missing) #endif - -#if defined(DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF) -#error DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF is deprecated, use DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF +#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16) +#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing) #endif - -#if defined(DUK_OPT_NO_JSONX) -#error DUK_OPT_NO_JSONX is deprecated, use DUK_OPT_NO_JX +#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER) +#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing) #endif - -#if defined(DUK_OPT_NO_JSONC) -#error DUK_OPT_NO_JSONC is deprecated, use DUK_OPT_NO_JC +#if defined(DUK_USE_DEEP_C_STACK) +#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK +#endif +#if defined(DUK_USE_DOUBLE_BE) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_BE +#endif +#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_LE) +#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_LE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_ME) +#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_LE) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_LE +#endif +#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_BE) +#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_BE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_ME) +#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_ME (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_ME) +#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_ME +#endif +#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_LE) +#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_LE (which is also defined) +#endif +#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_BE) +#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_BE (which is also defined) #endif - -/* - * Debug print consistency - */ - #if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG) -#error DUK_USE_DPRINT without DUK_USE_DEBUG +#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing) #endif - -#if defined(DUK_USE_DDPRINT) && !defined(DUK_USE_DEBUG) -#error DUK_USE_DDPRINT without DUK_USE_DEBUG +#if defined(DUK_USE_ESBC_MAX_BYTES) && !defined(DUK_USE_ESBC_LIMITS) +#error config option DUK_USE_ESBC_MAX_BYTES requires option DUK_USE_ESBC_LIMITS (which is missing) #endif - -#if defined(DUK_USE_DDDPRINT) && !defined(DUK_USE_DEBUG) -#error DUK_USE_DDDPRINT without DUK_USE_DEBUG +#if defined(DUK_USE_ESBC_MAX_LINENUMBER) && !defined(DUK_USE_ESBC_LIMITS) +#error config option DUK_USE_ESBC_MAX_LINENUMBER requires option DUK_USE_ESBC_LIMITS (which is missing) +#endif +#if defined(DUK_USE_EXEC_TIMEOUT_CHECK) && !defined(DUK_USE_INTERRUPT_COUNTER) +#error config option DUK_USE_EXEC_TIMEOUT_CHECK requires option DUK_USE_INTERRUPT_COUNTER (which is missing) +#endif +#if defined(DUK_USE_EXTSTR_FREE) && !defined(DUK_USE_HSTRING_EXTDATA) +#error config option DUK_USE_EXTSTR_FREE requires option DUK_USE_HSTRING_EXTDATA (which is missing) +#endif +#if defined(DUK_USE_EXTSTR_INTERN_CHECK) && !defined(DUK_USE_HSTRING_EXTDATA) +#error config option DUK_USE_EXTSTR_INTERN_CHECK requires option DUK_USE_HSTRING_EXTDATA (which is missing) +#endif +#if defined(DUK_USE_FULL_TVAL) +#error unsupported config option used (option has been removed): DUK_USE_FULL_TVAL +#endif +#if defined(DUK_USE_FUNCPTR_DEC16) && !defined(DUK_USE_FUNCPTR16) +#error config option DUK_USE_FUNCPTR_DEC16 requires option DUK_USE_FUNCPTR16 (which is missing) +#endif +#if defined(DUK_USE_FUNCPTR_ENC16) && !defined(DUK_USE_FUNCPTR16) +#error config option DUK_USE_FUNCPTR_ENC16 requires option DUK_USE_FUNCPTR16 (which is missing) +#endif +#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS) +#error unsupported config option used (option has been removed): DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS #endif - #if defined(DUK_USE_HEAPPTR16) && defined(DUK_USE_DEBUG) -/* Debug code doesn't have access to 'heap' so it cannot decode pointers. */ -#error debug printing cannot currently be used with heap pointer compression +#error config option DUK_USE_HEAPPTR16 conflicts with option DUK_USE_DEBUG (which is also defined) +#endif +#if defined(DUK_USE_HEAPPTR_DEC16) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_HEAPPTR_DEC16 requires option DUK_USE_HEAPPTR16 (which is missing) +#endif +#if defined(DUK_USE_HEAPPTR_ENC16) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_HEAPPTR_ENC16 requires option DUK_USE_HEAPPTR16 (which is missing) +#endif +#if defined(DUK_USE_INTEGER_BE) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_BE +#endif +#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_LE) +#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_LE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_ME) +#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_ME (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_LE) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_LE +#endif +#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_BE) +#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_BE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_ME) +#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_ME (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_ME) +#error unsupported config option used (option has been removed): DUK_USE_INTEGER_ME +#endif +#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_LE) +#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_LE (which is also defined) +#endif +#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE) +#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined) +#endif +#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST) +#error unsupported config option used (option has been removed): DUK_USE_NO_DOUBLE_ALIASING_SELFTEST +#endif +#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) +#error unsupported config option used (option has been removed): DUK_USE_PACKED_TVAL_POSSIBLE +#endif +#if defined(DUK_USE_RDTSC) +#error unsupported config option used (option has been removed): DUK_USE_RDTSC +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_CLONE) && defined(DUK_USE_ROM_GLOBAL_INHERIT) +#error config option DUK_USE_ROM_GLOBAL_CLONE conflicts with option DUK_USE_ROM_GLOBAL_INHERIT (which is also defined) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && defined(DUK_USE_ROM_GLOBAL_CLONE) +#error config option DUK_USE_ROM_GLOBAL_INHERIT conflicts with option DUK_USE_ROM_GLOBAL_CLONE (which is also defined) +#endif +#if defined(DUK_USE_ROM_OBJECTS) && !defined(DUK_USE_ROM_STRINGS) +#error config option DUK_USE_ROM_OBJECTS requires option DUK_USE_ROM_STRINGS (which is missing) +#endif +#if defined(DUK_USE_ROM_STRINGS) && !defined(DUK_USE_ROM_OBJECTS) +#error config option DUK_USE_ROM_STRINGS requires option DUK_USE_ROM_OBJECTS (which is missing) +#endif +#if defined(DUK_USE_SETJMP) +#error unsupported config option used (option has been removed): DUK_USE_SETJMP +#endif +#if defined(DUK_USE_SIGSETJMP) +#error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP +#endif +#if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN) +#error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing) +#endif +#if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) +#error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined) +#endif +#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) +#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE +#endif +#if defined(DUK_USE_UNDERSCORE_SETJMP) +#error unsupported config option used (option has been removed): DUK_USE_UNDERSCORE_SETJMP +#endif + +#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus) +#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler #endif /* - * Debugger consistency + * Convert DUK_USE_BYTEORDER, from whatever source, into currently used + * internal defines. If detection failed, #error out. */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) -#if !defined(DUK_USE_INTERRUPT_COUNTER) -#error DUK_USE_INTERRUPT_COUNTER is needed when debugger support is enabled -#endif -#if !defined(DUK_USE_PC2LINE) -#error DUK_USE_PC2LINE is needed when debugger support is enabled -#endif -#endif - -/* - * Garbage collection consistency - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) && !defined(DUK_USE_DOUBLE_LINKED_HEAP) -#error DUK_USE_REFERENCE_COUNTING defined without DUK_USE_DOUBLE_LINKED_HEAP -#endif - -#if defined(DUK_USE_GC_TORTURE) && !defined(DUK_USE_MARK_AND_SWEEP) -#error DUK_USE_GC_TORTURE defined without DUK_USE_MARK_AND_SWEEP -#endif - -/* - * Low memory feature consistency - */ - -#if defined(DUK_USE_OBJSIZES16) -#if defined(DUK_USE_HOBJECT_HASH_PART) -#error DUK_USE_OBJSIZES16 assumes DUK_USE_HOBJECT_HASH_PART is not defined -#endif -#endif - -#if defined(DUK_USE_STRTAB_CHAIN) && defined(DUK_USE_STRTAB_PROBE) -#error both DUK_USE_STRTAB_CHAIN and DUK_USE_STRTAB_PROBE defined -#endif -#if !defined(DUK_USE_STRTAB_CHAIN) && !defined(DUK_USE_STRTAB_PROBE) -#error neither DUK_USE_STRTAB_CHAIN nor DUK_USE_STRTAB_PROBE is defined -#endif +#if defined(DUK_USE_BYTEORDER) +#if (DUK_USE_BYTEORDER == 1) +#define DUK_USE_INTEGER_LE +#define DUK_USE_DOUBLE_LE +#elif (DUK_USE_BYTEORDER == 2) +#define DUK_USE_INTEGER_LE /* integer endianness is little on purpose */ +#define DUK_USE_DOUBLE_ME +#elif (DUK_USE_BYTEORDER == 3) +#define DUK_USE_INTEGER_BE +#define DUK_USE_DOUBLE_BE +#else +#error unsupported: byte order invalid +#endif /* byte order */ +#else +#error unsupported: byte order detection failed +#endif /* defined(DUK_USE_BYTEORDER) */ #endif /* DUK_CONFIG_H_INCLUDED */ diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/src-noline/duktape.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/src-noline/duktape.c new file mode 100644 index 000000000..9a65f55a2 --- /dev/null +++ b/ceph/src/civetweb/src/third_party/duktape-1.5.2/src-noline/duktape.c @@ -0,0 +1,86570 @@ +/* + * Single source autogenerated distributable for Duktape 1.5.2. + * + * Git commit cad34ae155acb0846545ca6bf2d29f9463b22bbb (v1.5.2). + * Git branch HEAD. + * + * See Duktape AUTHORS.rst and LICENSE.txt for copyright and + * licensing information. + */ + +/* LICENSE.txt */ +/* +* =============== +* Duktape license +* =============== +* +* (http://opensource.org/licenses/MIT) +* +* Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst) +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ +/* AUTHORS.rst */ +/* +* =============== +* Duktape authors +* =============== +* +* Copyright +* ========= +* +* Duktape copyrights are held by its authors. Each author has a copyright +* to their contribution, and agrees to irrevocably license the contribution +* under the Duktape ``LICENSE.txt``. +* +* Authors +* ======= +* +* Please include an e-mail address, a link to your GitHub profile, or something +* similar to allow your contribution to be identified accurately. +* +* The following people have contributed code, website contents, or Wiki contents, +* and agreed to irrevocably license their contributions under the Duktape +* ``LICENSE.txt`` (in order of appearance): +* +* * Sami Vaarala +* * Niki Dobrev +* * Andreas \u00d6man +* * L\u00e1szl\u00f3 Lang\u00f3 +* * Legimet +* * Karl Skomski +* * Bruce Pascoe +* * Ren\u00e9 Hollander +* * Julien Hamaide (https://github.com/crazyjul) +* * Sebastian G\u00f6tte (https://github.com/jaseg) +* +* Other contributions +* =================== +* +* The following people have contributed something other than code (e.g. reported +* bugs, provided ideas, etc; roughly in order of appearance): +* +* * Greg Burns +* * Anthony Rabine +* * Carlos Costa +* * Aur\u00e9lien Bouilland +* * Preet Desai (Pris Matic) +* * judofyr (http://www.reddit.com/user/judofyr) +* * Jason Woofenden +* * Micha\u0142 Przyby\u015b +* * Anthony Howe +* * Conrad Pankoff +* * Jim Schimpf +* * Rajaran Gaunker (https://github.com/zimbabao) +* * Andreas \u00d6man +* * Doug Sanden +* * Josh Engebretson (https://github.com/JoshEngebretson) +* * Remo Eichenberger (https://github.com/remoe) +* * Mamod Mehyar (https://github.com/mamod) +* * David Demelier (https://github.com/markand) +* * Tim Caswell (https://github.com/creationix) +* * Mitchell Blank Jr (https://github.com/mitchblank) +* * https://github.com/yushli +* * Seo Sanghyeon (https://github.com/sanxiyn) +* * Han ChoongWoo (https://github.com/tunz) +* * Joshua Peek (https://github.com/josh) +* * Bruce E. Pascoe (https://github.com/fatcerberus) +* * https://github.com/Kelledin +* * https://github.com/sstruchtrup +* * Michael Drake (https://github.com/tlsa) +* * https://github.com/chris-y +* * Laurent Zubiaur (https://github.com/lzubiaur) +* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr) +* +* If you are accidentally missing from this list, send me an e-mail +* (``sami.vaarala@iki.fi``) and I'll fix the omission. +*/ +/* + * Top-level include file to be used for all (internal) source files. + * + * Source files should not include individual header files, as they + * have not been designed to be individually included. + */ + +#ifndef DUK_INTERNAL_H_INCLUDED +#define DUK_INTERNAL_H_INCLUDED + +/* + * The 'duktape.h' header provides the public API, but also handles all + * compiler and platform specific feature detection, Duktape feature + * resolution, inclusion of system headers, etc. These have been merged + * because the public API is also dependent on e.g. detecting appropriate + * C types which is quite platform/compiler specific especially for a non-C99 + * build. The public API is also dependent on the resolved feature set. + * + * Some actions taken by the merged header (such as including system headers) + * are not appropriate for building a user application. The define + * DUK_COMPILING_DUKTAPE allows the merged header to skip/include some + * sections depending on what is being built. + */ + +#define DUK_COMPILING_DUKTAPE +#include "duktape.h" + +/* + * User declarations, e.g. prototypes for user functions used by Duktape + * macros. Concretely, if DUK_USE_PANIC_HANDLER is used and the macro + * value calls a user function, it needs to be declared for Duktape + * compilation to avoid warnings. + */ + +DUK_USE_USER_DECLARE() + +/* + * Duktape includes (other than duk_features.h) + * + * The header files expect to be included in an order which satisfies header + * dependencies correctly (the headers themselves don't include any other + * includes). Forward declarations are used to break circular struct/typedef + * dependencies. + */ + +#ifndef DUK_REPLACEMENTS_H_INCLUDED +#define DUK_REPLACEMENTS_H_INCLUDED + +#if !defined(DUK_SINGLE_FILE) +#if defined(DUK_USE_COMPUTED_INFINITY) +DUK_INTERNAL_DECL double duk_computed_infinity; +#endif +#if defined(DUK_USE_COMPUTED_NAN) +DUK_INTERNAL_DECL double duk_computed_nan; +#endif +#if defined(DUK_USE_REPL_FPCLASSIFY) +DUK_INTERNAL_DECL int duk_repl_fpclassify(double x); +#endif +#if defined(DUK_USE_REPL_SIGNBIT) +DUK_INTERNAL_DECL int duk_repl_signbit(double x); +#endif +#if defined(DUK_USE_REPL_ISFINITE) +DUK_INTERNAL_DECL int duk_repl_isfinite(double x); +#endif +#if defined(DUK_USE_REPL_ISNAN) +DUK_INTERNAL_DECL int duk_repl_isnan(double x); +#endif +#if defined(DUK_USE_REPL_ISINF) +DUK_INTERNAL_DECL int duk_repl_isinf(double x); +#endif +#endif /* !DUK_SINGLE_FILE */ + +#endif /* DUK_REPLACEMENTS_H_INCLUDED */ +/* + * Wrapper for jmp_buf. + * + * This is used because jmp_buf is an array type for backward compatibility. + * Wrapping jmp_buf in a struct makes pointer references, sizeof, etc, + * behave more intuitively. + * + * http://en.wikipedia.org/wiki/Setjmp.h#Member_types + */ + +#ifndef DUK_JMPBUF_H_INCLUDED +#define DUK_JMPBUF_H_INCLUDED + +#if defined(DUK_USE_CPP_EXCEPTIONS) +struct duk_jmpbuf { + duk_small_int_t dummy; /* unused */ +}; +#else +struct duk_jmpbuf { + DUK_JMPBUF_TYPE jb; +}; +#endif + +#endif /* DUK_JMPBUF_H_INCLUDED */ +/* + * Exception for Duktape internal throws when C++ exceptions are used + * for long control transfers. + * + * Doesn't inherit from any exception base class to minimize the chance + * that user code would accidentally catch this exception. + */ + +#ifndef DUK_EXCEPTION_H_INCLUDED +#define DUK_EXCEPTION_H_INCLUDED + +#if defined(DUK_USE_CPP_EXCEPTIONS) +class duk_internal_exception { + /* intentionally empty */ +}; +#endif + +#endif /* DUK_EXCEPTION_H_INCLUDED */ +/* + * Forward declarations for all Duktape structures. + */ + +#ifndef DUK_FORWDECL_H_INCLUDED +#define DUK_FORWDECL_H_INCLUDED + +/* + * Forward declarations + */ + +#if defined(DUK_USE_CPP_EXCEPTIONS) +class duk_internal_exception; +#else +struct duk_jmpbuf; +#endif + +/* duk_tval intentionally skipped */ +struct duk_heaphdr; +struct duk_heaphdr_string; +struct duk_hstring; +struct duk_hstring_external; +struct duk_hobject; +struct duk_hcompiledfunction; +struct duk_hnativefunction; +struct duk_hthread; +struct duk_hbufferobject; +struct duk_hbuffer; +struct duk_hbuffer_fixed; +struct duk_hbuffer_dynamic; +struct duk_hbuffer_external; + +struct duk_propaccessor; +union duk_propvalue; +struct duk_propdesc; + +struct duk_heap; +struct duk_breakpoint; + +struct duk_activation; +struct duk_catcher; +struct duk_strcache; +struct duk_ljstate; +struct duk_strtab_entry; + +#ifdef DUK_USE_DEBUG +struct duk_fixedbuffer; +#endif + +struct duk_bitdecoder_ctx; +struct duk_bitencoder_ctx; +struct duk_bufwriter_ctx; + +struct duk_token; +struct duk_re_token; +struct duk_lexer_point; +struct duk_lexer_ctx; +struct duk_lexer_codepoint; + +struct duk_compiler_instr; +struct duk_compiler_func; +struct duk_compiler_ctx; + +struct duk_re_matcher_ctx; +struct duk_re_compiler_ctx; + +#if defined(DUK_USE_CPP_EXCEPTIONS) +/* no typedef */ +#else +typedef struct duk_jmpbuf duk_jmpbuf; +#endif + +/* duk_tval intentionally skipped */ +typedef struct duk_heaphdr duk_heaphdr; +typedef struct duk_heaphdr_string duk_heaphdr_string; +typedef struct duk_hstring duk_hstring; +typedef struct duk_hstring_external duk_hstring_external; +typedef struct duk_hobject duk_hobject; +typedef struct duk_hcompiledfunction duk_hcompiledfunction; +typedef struct duk_hnativefunction duk_hnativefunction; +typedef struct duk_hbufferobject duk_hbufferobject; +typedef struct duk_hthread duk_hthread; +typedef struct duk_hbuffer duk_hbuffer; +typedef struct duk_hbuffer_fixed duk_hbuffer_fixed; +typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic; +typedef struct duk_hbuffer_external duk_hbuffer_external; + +typedef struct duk_propaccessor duk_propaccessor; +typedef union duk_propvalue duk_propvalue; +typedef struct duk_propdesc duk_propdesc; + +typedef struct duk_heap duk_heap; +typedef struct duk_breakpoint duk_breakpoint; + +typedef struct duk_activation duk_activation; +typedef struct duk_catcher duk_catcher; +typedef struct duk_strcache duk_strcache; +typedef struct duk_ljstate duk_ljstate; +typedef struct duk_strtab_entry duk_strtab_entry; + +#ifdef DUK_USE_DEBUG +typedef struct duk_fixedbuffer duk_fixedbuffer; +#endif + +typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx; +typedef struct duk_bitencoder_ctx duk_bitencoder_ctx; +typedef struct duk_bufwriter_ctx duk_bufwriter_ctx; + +typedef struct duk_token duk_token; +typedef struct duk_re_token duk_re_token; +typedef struct duk_lexer_point duk_lexer_point; +typedef struct duk_lexer_ctx duk_lexer_ctx; +typedef struct duk_lexer_codepoint duk_lexer_codepoint; + +typedef struct duk_compiler_instr duk_compiler_instr; +typedef struct duk_compiler_func duk_compiler_func; +typedef struct duk_compiler_ctx duk_compiler_ctx; + +typedef struct duk_re_matcher_ctx duk_re_matcher_ctx; +typedef struct duk_re_compiler_ctx duk_re_compiler_ctx; + +#endif /* DUK_FORWDECL_H_INCLUDED */ +/* + * Tagged type definition (duk_tval) and accessor macros. + * + * Access all fields through the accessor macros, as the representation + * is quite tricky. + * + * There are two packed type alternatives: an 8-byte representation + * based on an IEEE double (preferred for compactness), and a 12-byte + * representation (portability). The latter is needed also in e.g. + * 64-bit environments (it usually pads to 16 bytes per value). + * + * Selecting the tagged type format involves many trade-offs (memory + * use, size and performance of generated code, portability, etc), + * see doc/types.rst for a detailed discussion (especially of how the + * IEEE double format is used to pack tagged values). + * + * NB: because macro arguments are often expressions, macros should + * avoid evaluating their argument more than once. + */ + +#ifndef DUK_TVAL_H_INCLUDED +#define DUK_TVAL_H_INCLUDED + +/* sanity */ +#if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE) +#error unsupported: cannot determine byte order variant +#endif + +#if defined(DUK_USE_PACKED_TVAL) +/* ======================================================================== */ + +/* + * Packed 8-byte representation + */ + +/* use duk_double_union as duk_tval directly */ +typedef union duk_double_union duk_tval; + +/* tags */ +#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */ +/* avoid tag 0xfff0, no risk of confusion with negative infinity */ +#if defined(DUK_USE_FASTINT) +#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */ +#endif +#define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */ +#define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */ +#define DUK_TAG_NULL 0xfff4UL /* embed: nothing */ +#define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */ +/* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */ +#define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */ +#define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */ +#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */ +#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */ +#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */ + +/* for convenience */ +#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL +#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL + +/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */ +#if defined(DUK_USE_64BIT_OPS) +#if defined(DUK_USE_DOUBLE_ME) +#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \ + (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \ + } while (0) +#else +#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \ + (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \ + } while (0) +#endif +#else /* DUK_USE_64BIT_OPS */ +#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \ + (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \ + (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \ + } while (0) +#endif /* DUK_USE_64BIT_OPS */ + +#if defined(DUK_USE_64BIT_OPS) +/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */ +#if defined(DUK_USE_DOUBLE_ME) +#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \ + (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \ + ((duk_uint64_t) (flags)) | \ + (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \ + } while (0) +#else +#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \ + (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \ + (((duk_uint64_t) (flags)) << 32) | \ + ((duk_uint64_t) (duk_uint32_t) (fp)); \ + } while (0) +#endif +#else /* DUK_USE_64BIT_OPS */ +#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \ + (v)->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \ + (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \ + } while (0) +#endif /* DUK_USE_64BIT_OPS */ + +#if defined(DUK_USE_FASTINT) +/* Note: masking is done for 'i' to deal with negative numbers correctly */ +#if defined(DUK_USE_DOUBLE_ME) +#define DUK__TVAL_SET_FASTINT(v,i) do { \ + (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \ + (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ + } while (0) +#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \ + (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \ + (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ + } while (0) +#else +#define DUK__TVAL_SET_FASTINT(v,i) do { \ + (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \ + } while (0) +#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \ + (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \ + } while (0) +#endif + +#define DUK__TVAL_SET_FASTINT_I32(v,i) do { \ + duk_int64_t duk__tmp = (duk_int64_t) (i); \ + DUK_TVAL_SET_FASTINT((v), duk__tmp); \ + } while (0) + +/* XXX: clumsy sign extend and masking of 16 topmost bits */ +#if defined(DUK_USE_DOUBLE_ME) +#define DUK__TVAL_GET_FASTINT(v) (((duk_int64_t) ((((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16) +#else +#define DUK__TVAL_GET_FASTINT(v) ((((duk_int64_t) (v)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16) +#endif +#define DUK__TVAL_GET_FASTINT_U32(v) ((v)->ui[DUK_DBL_IDX_UI1]) +#define DUK__TVAL_GET_FASTINT_I32(v) ((duk_int32_t) (v)->ui[DUK_DBL_IDX_UI1]) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_UNDEFINED(v) do { \ + (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \ + } while (0) +#define DUK_TVAL_SET_UNUSED(v) do { \ + (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \ + } while (0) +#define DUK_TVAL_SET_NULL(v) do { \ + (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val))) + +#define DUK_TVAL_SET_NAN(v) DUK_DBLUNION_SET_NAN_FULL((v)) + +/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */ +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_DOUBLE(v,d) do { \ + duk_double_t duk__dblval; \ + duk__dblval = (d); \ + DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ + DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \ + } while (0) +#define DUK_TVAL_SET_FASTINT(v,i) DUK__TVAL_SET_FASTINT((v), (i)) +#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK__TVAL_SET_FASTINT_I32((v), (i)) +#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK__TVAL_SET_FASTINT_U32((v), (i)) +#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) duk_tval_set_number_chkfast((v), (d)) +#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d)) +#define DUK_TVAL_CHKFAST_INPLACE(v) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (v); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \ + } \ + } while (0) +#else +#define DUK_TVAL_SET_DOUBLE(v,d) do { \ + duk_double_t duk__dblval; \ + duk__dblval = (d); \ + DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ + DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \ + } while (0) +#define DUK_TVAL_SET_FASTINT(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) /* XXX: fast int-to-double */ +#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) +#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) +#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) DUK_TVAL_SET_DOUBLE((v), (d)) +#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d)) +#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0) +#endif + +#define DUK_TVAL_SET_LIGHTFUNC(v,fp,flags) DUK__TVAL_SET_LIGHTFUNC((v), (fp), (flags)) +#define DUK_TVAL_SET_STRING(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_STRING) +#define DUK_TVAL_SET_OBJECT(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_OBJECT) +#define DUK_TVAL_SET_BUFFER(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_BUFFER) +#define DUK_TVAL_SET_POINTER(v,p) DUK__TVAL_SET_TAGGEDPOINTER((v), (p), DUK_TAG_POINTER) + +#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0) + +/* getters */ +#define DUK_TVAL_GET_BOOLEAN(v) ((int) (v)->us[DUK_DBL_IDX_US1]) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_GET_DOUBLE(v) ((v)->d) +#define DUK_TVAL_GET_FASTINT(v) DUK__TVAL_GET_FASTINT((v)) +#define DUK_TVAL_GET_FASTINT_U32(v) DUK__TVAL_GET_FASTINT_U32((v)) +#define DUK_TVAL_GET_FASTINT_I32(v) DUK__TVAL_GET_FASTINT_I32((v)) +#define DUK_TVAL_GET_NUMBER(v) duk_tval_get_number_packed((v)) +#else +#define DUK_TVAL_GET_NUMBER(v) ((v)->d) +#define DUK_TVAL_GET_DOUBLE(v) ((v)->d) +#endif +#define DUK_TVAL_GET_LIGHTFUNC(v,out_fp,out_flags) do { \ + (out_flags) = (v)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \ + (out_fp) = (duk_c_function) (v)->ui[DUK_DBL_IDX_UI1]; \ + } while (0) +#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(v) ((duk_c_function) ((v)->ui[DUK_DBL_IDX_UI1])) +#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(v) (((int) (v)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL) +#define DUK_TVAL_GET_STRING(v) ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_OBJECT(v) ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_BUFFER(v) ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_POINTER(v) ((void *) (v)->vp[DUK_DBL_IDX_VP1]) +#define DUK_TVAL_GET_HEAPHDR(v) ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1]) + +/* decoding */ +#define DUK_TVAL_GET_TAG(v) ((duk_small_uint_t) (v)->us[DUK_DBL_IDX_US0]) + +#define DUK_TVAL_IS_UNDEFINED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED) +#define DUK_TVAL_IS_UNUSED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNUSED) +#define DUK_TVAL_IS_NULL(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL) +#define DUK_TVAL_IS_BOOLEAN(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN) +#define DUK_TVAL_IS_BOOLEAN_TRUE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE) +#define DUK_TVAL_IS_BOOLEAN_FALSE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE) +#define DUK_TVAL_IS_LIGHTFUNC(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_LIGHTFUNC) +#define DUK_TVAL_IS_STRING(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING) +#define DUK_TVAL_IS_OBJECT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT) +#define DUK_TVAL_IS_BUFFER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER) +#define DUK_TVAL_IS_POINTER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER) +#if defined(DUK_USE_FASTINT) +/* 0xfff0 is -Infinity */ +#define DUK_TVAL_IS_DOUBLE(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL) +#define DUK_TVAL_IS_FASTINT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_FASTINT) +#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff1UL) +#else +#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL) +#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v)) +#endif + +/* This is performance critical because it appears in every DECREF. */ +#define DUK_TVAL_IS_HEAP_ALLOCATED(v) (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING) + +#if defined(DUK_USE_FASTINT) +DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv); +#endif + +#else /* DUK_USE_PACKED_TVAL */ +/* ======================================================================== */ + +/* + * Portable 12-byte representation + */ + +/* Note: not initializing all bytes is normally not an issue: Duktape won't + * read or use the uninitialized bytes so valgrind won't issue warnings. + * In some special cases a harmless valgrind warning may be issued though. + * For example, the DumpHeap debugger command writes out a compiled function's + * 'data' area as is, including any uninitialized bytes, which causes a + * valgrind warning. + */ + +typedef struct duk_tval_struct duk_tval; + +struct duk_tval_struct { + duk_small_uint_t t; + duk_small_uint_t v_extra; + union { + duk_double_t d; + duk_small_int_t i; +#if defined(DUK_USE_FASTINT) + duk_int64_t fi; /* if present, forces 16-byte duk_tval */ +#endif + void *voidptr; + duk_hstring *hstring; + duk_hobject *hobject; + duk_hcompiledfunction *hcompiledfunction; + duk_hnativefunction *hnativefunction; + duk_hthread *hthread; + duk_hbuffer *hbuffer; + duk_heaphdr *heaphdr; + duk_c_function lightfunc; + } v; +}; + +#define DUK__TAG_NUMBER 0 /* not exposed */ +#if defined(DUK_USE_FASTINT) +#define DUK_TAG_FASTINT 1 +#endif +#define DUK_TAG_UNDEFINED 2 +#define DUK_TAG_NULL 3 +#define DUK_TAG_BOOLEAN 4 +#define DUK_TAG_POINTER 5 +#define DUK_TAG_LIGHTFUNC 6 +#define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */ +#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */ +#define DUK_TAG_OBJECT 9 +#define DUK_TAG_BUFFER 10 + +/* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code + * to support the 8-byte representation. Further, it is a non-heap-allocated + * type so it should come before DUK_TAG_STRING. Finally, it should not break + * the tag value ranges covered by case-clauses in a switch-case. + */ + +/* setters */ +#define DUK_TVAL_SET_UNDEFINED(tv) do { \ + (tv)->t = DUK_TAG_UNDEFINED; \ + } while (0) + +#define DUK_TVAL_SET_UNUSED(tv) do { \ + (tv)->t = DUK_TAG_UNUSED; \ + } while (0) + +#define DUK_TVAL_SET_NULL(tv) do { \ + (tv)->t = DUK_TAG_NULL; \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \ + (tv)->t = DUK_TAG_BOOLEAN; \ + (tv)->v.i = (val); \ + } while (0) + +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_DOUBLE(tv,val) do { \ + (tv)->t = DUK__TAG_NUMBER; \ + (tv)->v.d = (val); \ + } while (0) +#define DUK_TVAL_SET_FASTINT(tv,val) do { \ + (tv)->t = DUK_TAG_FASTINT; \ + (tv)->v.fi = (val); \ + } while (0) +#define DUK_TVAL_SET_FASTINT_U32(tv,val) do { \ + (tv)->t = DUK_TAG_FASTINT; \ + (tv)->v.fi = (duk_int64_t) (val); \ + } while (0) +#define DUK_TVAL_SET_FASTINT_I32(tv,val) do { \ + (tv)->t = DUK_TAG_FASTINT; \ + (tv)->v.fi = (duk_int64_t) (val); \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \ + duk_tval_set_number_chkfast((tv), (d)) +#define DUK_TVAL_SET_NUMBER(tv,val) \ + DUK_TVAL_SET_DOUBLE((tv), (val)) +#define DUK_TVAL_CHKFAST_INPLACE(v) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (v); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \ + } \ + } while (0) +#else +#define DUK_TVAL_SET_DOUBLE(tv,d) \ + DUK_TVAL_SET_NUMBER((tv), (d)) +#define DUK_TVAL_SET_FASTINT(tv,val) \ + DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */ +#define DUK_TVAL_SET_FASTINT_U32(tv,val) \ + DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) +#define DUK_TVAL_SET_FASTINT_I32(tv,val) \ + DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) +#define DUK_TVAL_SET_NUMBER(tv,val) do { \ + (tv)->t = DUK__TAG_NUMBER; \ + (tv)->v.d = (val); \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \ + DUK_TVAL_SET_NUMBER((tv), (d)) +#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_POINTER(tv,hptr) do { \ + (tv)->t = DUK_TAG_POINTER; \ + (tv)->v.voidptr = (hptr); \ + } while (0) + +#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ + (tv)->t = DUK_TAG_LIGHTFUNC; \ + (tv)->v_extra = (flags); \ + (tv)->v.lightfunc = (duk_c_function) (fp); \ + } while (0) + +#define DUK_TVAL_SET_STRING(tv,hptr) do { \ + (tv)->t = DUK_TAG_STRING; \ + (tv)->v.hstring = (hptr); \ + } while (0) + +#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \ + (tv)->t = DUK_TAG_OBJECT; \ + (tv)->v.hobject = (hptr); \ + } while (0) + +#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \ + (tv)->t = DUK_TAG_BUFFER; \ + (tv)->v.hbuffer = (hptr); \ + } while (0) + +#define DUK_TVAL_SET_NAN(tv) do { \ + /* in non-packed representation we don't care about which NaN is used */ \ + (tv)->t = DUK__TAG_NUMBER; \ + (tv)->v.d = DUK_DOUBLE_NAN; \ + } while (0) + +#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0) + +/* getters */ +#define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) +#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi) +#define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi)) +#define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi)) +#if 0 +#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ + (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \ + DUK_TVAL_GET_DOUBLE((tv))) +#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv)) +#else +/* This seems reasonable overall. */ +#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ + duk_tval_get_number_unpacked_fastint((tv)) : \ + DUK_TVAL_GET_DOUBLE((tv))) +#endif +#else +#define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d) +#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr) +#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ + (out_flags) = (duk_uint32_t) (tv)->v_extra; \ + (out_fp) = (tv)->v.lightfunc; \ + } while (0) +#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc) +#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra)) +#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring) +#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject) +#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer) +#define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr) + +/* decoding */ +#define DUK_TVAL_GET_TAG(tv) ((tv)->t) +#define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED) +#define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED) +#define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL) +#define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN) +#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0)) +#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0)) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK__TAG_NUMBER) +#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT) +#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER || \ + (tv)->t == DUK_TAG_FASTINT) +#else +#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER) +#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v)) +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER) +#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC) +#define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING) +#define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT) +#define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER) + +/* This is performance critical because it's needed for every DECREF. + * Take advantage of the fact that the first heap allocated tag is 8, + * so that bit 3 is set for all heap allocated tags (and never set for + * non-heap-allocated tags). + */ +#if 0 +#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING) +#endif +#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08) + +#if defined(DUK_USE_FASTINT) +#if 0 +DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv); +#endif +DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv); +#endif + +#endif /* DUK_USE_PACKED_TVAL */ + +/* + * Convenience (independent of representation) + */ + +#define DUK_TVAL_SET_BOOLEAN_TRUE(v) DUK_TVAL_SET_BOOLEAN(v, 1) +#define DUK_TVAL_SET_BOOLEAN_FALSE(v) DUK_TVAL_SET_BOOLEAN(v, 0) + +/* Lightfunc flags packing and unpacking. */ +/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss## */ +#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \ + ((((duk_int32_t) (lf_flags)) << 16) >> 24) +#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \ + (((lf_flags) >> 4) & 0x0f) +#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \ + ((lf_flags) & 0x0f) +#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \ + (((magic) & 0xff) << 8) | ((length) << 4) | (nargs) + +#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */ +#define DUK_LFUNC_NARGS_MIN 0x00 +#define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */ +#define DUK_LFUNC_LENGTH_MIN 0x00 +#define DUK_LFUNC_LENGTH_MAX 0x0f +#define DUK_LFUNC_MAGIC_MIN (-0x80) +#define DUK_LFUNC_MAGIC_MAX 0x7f + +/* fastint constants etc */ +#if defined(DUK_USE_FASTINT) +#define DUK_FASTINT_MIN (-0x800000000000LL) +#define DUK_FASTINT_MAX 0x7fffffffffffLL +#define DUK_FASTINT_BITS 48 + +DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x); +#endif + +#endif /* DUK_TVAL_H_INCLUDED */ +/* + * Automatically generated by genbuiltins.py, do not edit! + */ + +#ifndef DUK_BUILTINS_H_INCLUDED +#define DUK_BUILTINS_H_INCLUDED + +#if defined(DUK_USE_ROM_STRINGS) +#error ROM support not enabled, rerun make_dist.py with --rom-support +#else /* DUK_USE_ROM_STRINGS */ +#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */ +#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED) +#define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED) +#define DUK_STRIDX_UC_NULL 1 /* 'Null' */ +#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL) +#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL) +#define DUK_STRIDX_UC_ARGUMENTS 2 /* 'Arguments' */ +#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS) +#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS) +#define DUK_STRIDX_UC_OBJECT 3 /* 'Object' */ +#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT) +#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT) +#define DUK_STRIDX_UC_FUNCTION 4 /* 'Function' */ +#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION) +#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION) +#define DUK_STRIDX_ARRAY 5 /* 'Array' */ +#define DUK_HEAP_STRING_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY) +#define DUK_HTHREAD_STRING_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY) +#define DUK_STRIDX_UC_STRING 6 /* 'String' */ +#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING) +#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING) +#define DUK_STRIDX_UC_BOOLEAN 7 /* 'Boolean' */ +#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN) +#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN) +#define DUK_STRIDX_UC_NUMBER 8 /* 'Number' */ +#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER) +#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER) +#define DUK_STRIDX_DATE 9 /* 'Date' */ +#define DUK_HEAP_STRING_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE) +#define DUK_HTHREAD_STRING_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE) +#define DUK_STRIDX_REG_EXP 10 /* 'RegExp' */ +#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP) +#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP) +#define DUK_STRIDX_UC_ERROR 11 /* 'Error' */ +#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR) +#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR) +#define DUK_STRIDX_MATH 12 /* 'Math' */ +#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH) +#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH) +#define DUK_STRIDX_JSON 13 /* 'JSON' */ +#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON) +#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON) +#define DUK_STRIDX_EMPTY_STRING 14 /* '' */ +#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING) +#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING) +#define DUK_STRIDX_ARRAY_BUFFER 15 /* 'ArrayBuffer' */ +#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER) +#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER) +#define DUK_STRIDX_DATA_VIEW 16 /* 'DataView' */ +#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW) +#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW) +#define DUK_STRIDX_INT8_ARRAY 17 /* 'Int8Array' */ +#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY) +#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY) +#define DUK_STRIDX_UINT8_ARRAY 18 /* 'Uint8Array' */ +#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY) +#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY) +#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 19 /* 'Uint8ClampedArray' */ +#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY) +#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY) +#define DUK_STRIDX_INT16_ARRAY 20 /* 'Int16Array' */ +#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY) +#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY) +#define DUK_STRIDX_UINT16_ARRAY 21 /* 'Uint16Array' */ +#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY) +#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY) +#define DUK_STRIDX_INT32_ARRAY 22 /* 'Int32Array' */ +#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY) +#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY) +#define DUK_STRIDX_UINT32_ARRAY 23 /* 'Uint32Array' */ +#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY) +#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY) +#define DUK_STRIDX_FLOAT32_ARRAY 24 /* 'Float32Array' */ +#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY) +#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY) +#define DUK_STRIDX_FLOAT64_ARRAY 25 /* 'Float64Array' */ +#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY) +#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY) +#define DUK_STRIDX_GLOBAL 26 /* 'global' */ +#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL) +#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL) +#define DUK_STRIDX_OBJ_ENV 27 /* 'ObjEnv' */ +#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV) +#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV) +#define DUK_STRIDX_DEC_ENV 28 /* 'DecEnv' */ +#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV) +#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV) +#define DUK_STRIDX_UC_BUFFER 29 /* 'Buffer' */ +#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER) +#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER) +#define DUK_STRIDX_UC_POINTER 30 /* 'Pointer' */ +#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER) +#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER) +#define DUK_STRIDX_UC_THREAD 31 /* 'Thread' */ +#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD) +#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD) +#define DUK_STRIDX_EVAL 32 /* 'eval' */ +#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL) +#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL) +#define DUK_STRIDX_DEFINE_PROPERTY 33 /* 'defineProperty' */ +#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY) +#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY) +#define DUK_STRIDX_VALUE 34 /* 'value' */ +#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE) +#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE) +#define DUK_STRIDX_WRITABLE 35 /* 'writable' */ +#define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE) +#define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE) +#define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */ +#define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE) +#define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE) +#define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */ +#define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE) +#define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE) +#define DUK_STRIDX_JOIN 38 /* 'join' */ +#define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN) +#define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN) +#define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */ +#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING) +#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING) +#define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */ +#define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF) +#define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF) +#define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */ +#define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING) +#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING) +#define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */ +#define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING) +#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING) +#define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */ +#define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING) +#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING) +#define DUK_STRIDX_SOURCE 44 /* 'source' */ +#define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE) +#define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE) +#define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */ +#define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE) +#define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE) +#define DUK_STRIDX_MULTILINE 46 /* 'multiline' */ +#define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE) +#define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE) +#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */ +#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX) +#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX) +#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP 48 /* '(?:)' */ +#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP) +#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP) +#define DUK_STRIDX_INDEX 49 /* 'index' */ +#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX) +#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX) +#define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */ +#define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE) +#define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE) +#define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */ +#define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR) +#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR) +#define DUK_STRIDX_MESSAGE 52 /* 'message' */ +#define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE) +#define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE) +#define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */ +#define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN) +#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN) +#define DUK_STRIDX_LC_NUMBER 54 /* 'number' */ +#define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER) +#define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER) +#define DUK_STRIDX_LC_STRING 55 /* 'string' */ +#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING) +#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING) +#define DUK_STRIDX_LC_OBJECT 56 /* 'object' */ +#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT) +#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT) +#define DUK_STRIDX_LC_UNDEFINED 57 /* 'undefined' */ +#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED) +#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED) +#define DUK_STRIDX_NAN 58 /* 'NaN' */ +#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN) +#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN) +#define DUK_STRIDX_INFINITY 59 /* 'Infinity' */ +#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY) +#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY) +#define DUK_STRIDX_MINUS_INFINITY 60 /* '-Infinity' */ +#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY) +#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY) +#define DUK_STRIDX_MINUS_ZERO 61 /* '-0' */ +#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO) +#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO) +#define DUK_STRIDX_COMMA 62 /* ',' */ +#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA) +#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA) +#define DUK_STRIDX_SPACE 63 /* ' ' */ +#define DUK_HEAP_STRING_SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE) +#define DUK_HTHREAD_STRING_SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE) +#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */ +#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE) +#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE) +#define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */ +#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS) +#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS) +#define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */ +#define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE) +#define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE) +#define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */ +#define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS) +#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS) +#define DUK_STRIDX_CALLEE 68 /* 'callee' */ +#define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE) +#define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE) +#define DUK_STRIDX_CALLER 69 /* 'caller' */ +#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER) +#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER) +#define DUK_STRIDX_HAS 70 /* 'has' */ +#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS) +#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS) +#define DUK_STRIDX_GET 71 /* 'get' */ +#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET) +#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET) +#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */ +#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY) +#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY) +#define DUK_STRIDX_ENUMERATE 73 /* 'enumerate' */ +#define DUK_HEAP_STRING_ENUMERATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERATE) +#define DUK_HTHREAD_STRING_ENUMERATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERATE) +#define DUK_STRIDX_OWN_KEYS 74 /* 'ownKeys' */ +#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS) +#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS) +#define DUK_STRIDX_SET_PROTOTYPE_OF 75 /* 'setPrototypeOf' */ +#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF) +#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF) +#define DUK_STRIDX___PROTO__ 76 /* '__proto__' */ +#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__) +#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__) +#define DUK_STRIDX_REQUIRE 77 /* 'require' */ +#define DUK_HEAP_STRING_REQUIRE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REQUIRE) +#define DUK_HTHREAD_STRING_REQUIRE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REQUIRE) +#define DUK_STRIDX_ID 78 /* 'id' */ +#define DUK_HEAP_STRING_ID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ID) +#define DUK_HTHREAD_STRING_ID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ID) +#define DUK_STRIDX_EXPORTS 79 /* 'exports' */ +#define DUK_HEAP_STRING_EXPORTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORTS) +#define DUK_HTHREAD_STRING_EXPORTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORTS) +#define DUK_STRIDX_FILENAME 80 /* 'filename' */ +#define DUK_HEAP_STRING_FILENAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILENAME) +#define DUK_HTHREAD_STRING_FILENAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILENAME) +#define DUK_STRIDX_TO_STRING 81 /* 'toString' */ +#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING) +#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING) +#define DUK_STRIDX_TO_JSON 82 /* 'toJSON' */ +#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON) +#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON) +#define DUK_STRIDX_TYPE 83 /* 'type' */ +#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE) +#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE) +#define DUK_STRIDX_DATA 84 /* 'data' */ +#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA) +#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA) +#define DUK_STRIDX_LENGTH 85 /* 'length' */ +#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH) +#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH) +#define DUK_STRIDX_BYTE_LENGTH 86 /* 'byteLength' */ +#define DUK_HEAP_STRING_BYTE_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_LENGTH) +#define DUK_HTHREAD_STRING_BYTE_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_LENGTH) +#define DUK_STRIDX_BYTE_OFFSET 87 /* 'byteOffset' */ +#define DUK_HEAP_STRING_BYTE_OFFSET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_OFFSET) +#define DUK_HTHREAD_STRING_BYTE_OFFSET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_OFFSET) +#define DUK_STRIDX_BYTES_PER_ELEMENT 88 /* 'BYTES_PER_ELEMENT' */ +#define DUK_HEAP_STRING_BYTES_PER_ELEMENT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTES_PER_ELEMENT) +#define DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTES_PER_ELEMENT) +#define DUK_STRIDX_SET 89 /* 'set' */ +#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET) +#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET) +#define DUK_STRIDX_STACK 90 /* 'stack' */ +#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK) +#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK) +#define DUK_STRIDX_PC 91 /* 'pc' */ +#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC) +#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC) +#define DUK_STRIDX_LINE_NUMBER 92 /* 'lineNumber' */ +#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER) +#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER) +#define DUK_STRIDX_INT_TRACEDATA 93 /* '\xffTracedata' */ +#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA) +#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA) +#define DUK_STRIDX_NAME 94 /* 'name' */ +#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME) +#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME) +#define DUK_STRIDX_FILE_NAME 95 /* 'fileName' */ +#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME) +#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME) +#define DUK_STRIDX_LC_BUFFER 96 /* 'buffer' */ +#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER) +#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER) +#define DUK_STRIDX_LC_POINTER 97 /* 'pointer' */ +#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER) +#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER) +#define DUK_STRIDX_INT_VALUE 98 /* '\xffValue' */ +#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE) +#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE) +#define DUK_STRIDX_INT_NEXT 99 /* '\xffNext' */ +#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT) +#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT) +#define DUK_STRIDX_INT_BYTECODE 100 /* '\xffBytecode' */ +#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE) +#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE) +#define DUK_STRIDX_INT_FORMALS 101 /* '\xffFormals' */ +#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS) +#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS) +#define DUK_STRIDX_INT_VARMAP 102 /* '\xffVarmap' */ +#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP) +#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP) +#define DUK_STRIDX_INT_LEXENV 103 /* '\xffLexenv' */ +#define DUK_HEAP_STRING_INT_LEXENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV) +#define DUK_HTHREAD_STRING_INT_LEXENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV) +#define DUK_STRIDX_INT_VARENV 104 /* '\xffVarenv' */ +#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV) +#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV) +#define DUK_STRIDX_INT_SOURCE 105 /* '\xffSource' */ +#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE) +#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE) +#define DUK_STRIDX_INT_PC2LINE 106 /* '\xffPc2line' */ +#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE) +#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE) +#define DUK_STRIDX_INT_ARGS 107 /* '\xffArgs' */ +#define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS) +#define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS) +#define DUK_STRIDX_INT_MAP 108 /* '\xffMap' */ +#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP) +#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP) +#define DUK_STRIDX_INT_FINALIZER 109 /* '\xffFinalizer' */ +#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER) +#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER) +#define DUK_STRIDX_INT_HANDLER 110 /* '\xffHandler' */ +#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER) +#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER) +#define DUK_STRIDX_INT_CALLEE 111 /* '\xffCallee' */ +#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE) +#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE) +#define DUK_STRIDX_INT_THREAD 112 /* '\xffThread' */ +#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD) +#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD) +#define DUK_STRIDX_INT_REGBASE 113 /* '\xffRegbase' */ +#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE) +#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE) +#define DUK_STRIDX_INT_TARGET 114 /* '\xffTarget' */ +#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET) +#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET) +#define DUK_STRIDX_INT_THIS 115 /* '\xffThis' */ +#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS) +#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS) +#define DUK_STRIDX_COMPILE 116 /* 'compile' */ +#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE) +#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE) +#define DUK_STRIDX_INPUT 117 /* 'input' */ +#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT) +#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT) +#define DUK_STRIDX_ERR_CREATE 118 /* 'errCreate' */ +#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE) +#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE) +#define DUK_STRIDX_ERR_THROW 119 /* 'errThrow' */ +#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW) +#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW) +#define DUK_STRIDX_MOD_SEARCH 120 /* 'modSearch' */ +#define DUK_HEAP_STRING_MOD_SEARCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_SEARCH) +#define DUK_HTHREAD_STRING_MOD_SEARCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_SEARCH) +#define DUK_STRIDX_MOD_LOADED 121 /* 'modLoaded' */ +#define DUK_HEAP_STRING_MOD_LOADED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_LOADED) +#define DUK_HTHREAD_STRING_MOD_LOADED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_LOADED) +#define DUK_STRIDX_ENV 122 /* 'env' */ +#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV) +#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV) +#define DUK_STRIDX_HEX 123 /* 'hex' */ +#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX) +#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX) +#define DUK_STRIDX_BASE64 124 /* 'base64' */ +#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64) +#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64) +#define DUK_STRIDX_JX 125 /* 'jx' */ +#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX) +#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX) +#define DUK_STRIDX_JC 126 /* 'jc' */ +#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC) +#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC) +#define DUK_STRIDX_RESUME 127 /* 'resume' */ +#define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME) +#define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME) +#define DUK_STRIDX_FMT 128 /* 'fmt' */ +#define DUK_HEAP_STRING_FMT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT) +#define DUK_HTHREAD_STRING_FMT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT) +#define DUK_STRIDX_RAW 129 /* 'raw' */ +#define DUK_HEAP_STRING_RAW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW) +#define DUK_HTHREAD_STRING_RAW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW) +#define DUK_STRIDX_LC_TRACE 130 /* 'trace' */ +#define DUK_HEAP_STRING_LC_TRACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE) +#define DUK_HTHREAD_STRING_LC_TRACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE) +#define DUK_STRIDX_LC_DEBUG 131 /* 'debug' */ +#define DUK_HEAP_STRING_LC_DEBUG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG) +#define DUK_HTHREAD_STRING_LC_DEBUG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG) +#define DUK_STRIDX_LC_INFO 132 /* 'info' */ +#define DUK_HEAP_STRING_LC_INFO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO) +#define DUK_HTHREAD_STRING_LC_INFO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO) +#define DUK_STRIDX_LC_WARN 133 /* 'warn' */ +#define DUK_HEAP_STRING_LC_WARN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN) +#define DUK_HTHREAD_STRING_LC_WARN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN) +#define DUK_STRIDX_LC_ERROR 134 /* 'error' */ +#define DUK_HEAP_STRING_LC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR) +#define DUK_HTHREAD_STRING_LC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR) +#define DUK_STRIDX_LC_FATAL 135 /* 'fatal' */ +#define DUK_HEAP_STRING_LC_FATAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL) +#define DUK_HTHREAD_STRING_LC_FATAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL) +#define DUK_STRIDX_LC_N 136 /* 'n' */ +#define DUK_HEAP_STRING_LC_N(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N) +#define DUK_HTHREAD_STRING_LC_N(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N) +#define DUK_STRIDX_LC_L 137 /* 'l' */ +#define DUK_HEAP_STRING_LC_L(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L) +#define DUK_HTHREAD_STRING_LC_L(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L) +#define DUK_STRIDX_CLOG 138 /* 'clog' */ +#define DUK_HEAP_STRING_CLOG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG) +#define DUK_HTHREAD_STRING_CLOG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG) +#define DUK_STRIDX_TO_LOG_STRING 139 /* 'toLogString' */ +#define DUK_HEAP_STRING_TO_LOG_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING) +#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING) +#define DUK_STRIDX_JSON_EXT_UNDEFINED 140 /* '{"_undef":true}' */ +#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED) +#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED) +#define DUK_STRIDX_JSON_EXT_NAN 141 /* '{"_nan":true}' */ +#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN) +#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN) +#define DUK_STRIDX_JSON_EXT_POSINF 142 /* '{"_inf":true}' */ +#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF) +#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF) +#define DUK_STRIDX_JSON_EXT_NEGINF 143 /* '{"_ninf":true}' */ +#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF) +#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF) +#define DUK_STRIDX_JSON_EXT_FUNCTION1 144 /* '{"_func":true}' */ +#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1) +#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1) +#define DUK_STRIDX_JSON_EXT_FUNCTION2 145 /* '{_func:true}' */ +#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2) +#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2) +#define DUK_STRIDX_BREAK 146 /* 'break' */ +#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK) +#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK) +#define DUK_STRIDX_CASE 147 /* 'case' */ +#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE) +#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE) +#define DUK_STRIDX_CATCH 148 /* 'catch' */ +#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH) +#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH) +#define DUK_STRIDX_CONTINUE 149 /* 'continue' */ +#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE) +#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE) +#define DUK_STRIDX_DEBUGGER 150 /* 'debugger' */ +#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER) +#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER) +#define DUK_STRIDX_DEFAULT 151 /* 'default' */ +#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT) +#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT) +#define DUK_STRIDX_DELETE 152 /* 'delete' */ +#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE) +#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE) +#define DUK_STRIDX_DO 153 /* 'do' */ +#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO) +#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO) +#define DUK_STRIDX_ELSE 154 /* 'else' */ +#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE) +#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE) +#define DUK_STRIDX_FINALLY 155 /* 'finally' */ +#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY) +#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY) +#define DUK_STRIDX_FOR 156 /* 'for' */ +#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR) +#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR) +#define DUK_STRIDX_LC_FUNCTION 157 /* 'function' */ +#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION) +#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION) +#define DUK_STRIDX_IF 158 /* 'if' */ +#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF) +#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF) +#define DUK_STRIDX_IN 159 /* 'in' */ +#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN) +#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN) +#define DUK_STRIDX_INSTANCEOF 160 /* 'instanceof' */ +#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF) +#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF) +#define DUK_STRIDX_NEW 161 /* 'new' */ +#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW) +#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW) +#define DUK_STRIDX_RETURN 162 /* 'return' */ +#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN) +#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN) +#define DUK_STRIDX_SWITCH 163 /* 'switch' */ +#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH) +#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH) +#define DUK_STRIDX_THIS 164 /* 'this' */ +#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS) +#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS) +#define DUK_STRIDX_THROW 165 /* 'throw' */ +#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW) +#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW) +#define DUK_STRIDX_TRY 166 /* 'try' */ +#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY) +#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY) +#define DUK_STRIDX_TYPEOF 167 /* 'typeof' */ +#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF) +#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF) +#define DUK_STRIDX_VAR 168 /* 'var' */ +#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR) +#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR) +#define DUK_STRIDX_CONST 169 /* 'const' */ +#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) +#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) +#define DUK_STRIDX_VOID 170 /* 'void' */ +#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID) +#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID) +#define DUK_STRIDX_WHILE 171 /* 'while' */ +#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE) +#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE) +#define DUK_STRIDX_WITH 172 /* 'with' */ +#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH) +#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH) +#define DUK_STRIDX_CLASS 173 /* 'class' */ +#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS) +#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS) +#define DUK_STRIDX_ENUM 174 /* 'enum' */ +#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM) +#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM) +#define DUK_STRIDX_EXPORT 175 /* 'export' */ +#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT) +#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT) +#define DUK_STRIDX_EXTENDS 176 /* 'extends' */ +#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS) +#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS) +#define DUK_STRIDX_IMPORT 177 /* 'import' */ +#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT) +#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT) +#define DUK_STRIDX_SUPER 178 /* 'super' */ +#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER) +#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER) +#define DUK_STRIDX_LC_NULL 179 /* 'null' */ +#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL) +#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL) +#define DUK_STRIDX_TRUE 180 /* 'true' */ +#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE) +#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE) +#define DUK_STRIDX_FALSE 181 /* 'false' */ +#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE) +#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE) +#define DUK_STRIDX_IMPLEMENTS 182 /* 'implements' */ +#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS) +#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS) +#define DUK_STRIDX_INTERFACE 183 /* 'interface' */ +#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE) +#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE) +#define DUK_STRIDX_LET 184 /* 'let' */ +#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET) +#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET) +#define DUK_STRIDX_PACKAGE 185 /* 'package' */ +#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE) +#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE) +#define DUK_STRIDX_PRIVATE 186 /* 'private' */ +#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE) +#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE) +#define DUK_STRIDX_PROTECTED 187 /* 'protected' */ +#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED) +#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED) +#define DUK_STRIDX_PUBLIC 188 /* 'public' */ +#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC) +#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC) +#define DUK_STRIDX_STATIC 189 /* 'static' */ +#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC) +#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC) +#define DUK_STRIDX_YIELD 190 /* 'yield' */ +#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD) +#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD) + +#define DUK_HEAP_NUM_STRINGS 191 +#define DUK_STRIDX_START_RESERVED 146 +#define DUK_STRIDX_START_STRICT_RESERVED 182 +#define DUK_STRIDX_END_RESERVED 191 /* exclusive endpoint */ + +/* To convert a heap stridx to a token number, subtract + * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED. + */ +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[1049]; +#endif /* !DUK_SINGLE_FILE */ +#define DUK_STRDATA_MAX_STRLEN 17 +#define DUK_STRDATA_DATA_LENGTH 1049 +#endif /* DUK_USE_ROM_STRINGS */ + +#if defined(DUK_USE_ROM_OBJECTS) +#error ROM support not enabled, rerun make_dist.py with --rom-support +#else +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_require(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx); +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149]; +#endif /* !DUK_SINGLE_FILE */ +#if defined(DUK_USE_BUILTIN_INITJS) +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[204]; +#endif /* !DUK_SINGLE_FILE */ +#define DUK_BUILTIN_INITJS_DATA_LENGTH 204 +#endif /* DUK_USE_BUILTIN_INITJS */ +#define DUK_BIDX_GLOBAL 0 +#define DUK_BIDX_GLOBAL_ENV 1 +#define DUK_BIDX_OBJECT_CONSTRUCTOR 2 +#define DUK_BIDX_OBJECT_PROTOTYPE 3 +#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4 +#define DUK_BIDX_FUNCTION_PROTOTYPE 5 +#define DUK_BIDX_ARRAY_CONSTRUCTOR 6 +#define DUK_BIDX_ARRAY_PROTOTYPE 7 +#define DUK_BIDX_STRING_CONSTRUCTOR 8 +#define DUK_BIDX_STRING_PROTOTYPE 9 +#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 10 +#define DUK_BIDX_BOOLEAN_PROTOTYPE 11 +#define DUK_BIDX_NUMBER_CONSTRUCTOR 12 +#define DUK_BIDX_NUMBER_PROTOTYPE 13 +#define DUK_BIDX_DATE_CONSTRUCTOR 14 +#define DUK_BIDX_DATE_PROTOTYPE 15 +#define DUK_BIDX_REGEXP_CONSTRUCTOR 16 +#define DUK_BIDX_REGEXP_PROTOTYPE 17 +#define DUK_BIDX_ERROR_CONSTRUCTOR 18 +#define DUK_BIDX_ERROR_PROTOTYPE 19 +#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 20 +#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 21 +#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 22 +#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 23 +#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 24 +#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 25 +#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 26 +#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 27 +#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 28 +#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 29 +#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 30 +#define DUK_BIDX_URI_ERROR_PROTOTYPE 31 +#define DUK_BIDX_MATH 32 +#define DUK_BIDX_JSON 33 +#define DUK_BIDX_TYPE_ERROR_THROWER 34 +#define DUK_BIDX_PROXY_CONSTRUCTOR 35 +#define DUK_BIDX_DUKTAPE 36 +#define DUK_BIDX_THREAD_CONSTRUCTOR 37 +#define DUK_BIDX_THREAD_PROTOTYPE 38 +#define DUK_BIDX_BUFFER_CONSTRUCTOR 39 +#define DUK_BIDX_BUFFER_PROTOTYPE 40 +#define DUK_BIDX_POINTER_CONSTRUCTOR 41 +#define DUK_BIDX_POINTER_PROTOTYPE 42 +#define DUK_BIDX_LOGGER_CONSTRUCTOR 43 +#define DUK_BIDX_LOGGER_PROTOTYPE 44 +#define DUK_BIDX_DOUBLE_ERROR 45 +#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 46 +#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 47 +#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 48 +#define DUK_BIDX_DATAVIEW_PROTOTYPE 49 +#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 50 +#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 51 +#define DUK_BIDX_INT8ARRAY_PROTOTYPE 52 +#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 53 +#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 54 +#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 55 +#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 56 +#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 57 +#define DUK_BIDX_INT16ARRAY_PROTOTYPE 58 +#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 59 +#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 60 +#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 61 +#define DUK_BIDX_INT32ARRAY_PROTOTYPE 62 +#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 63 +#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 64 +#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 65 +#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 66 +#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 67 +#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 68 +#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 69 +#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 70 +#define DUK_NUM_BUILTINS 71 +#define DUK_NUM_BIDX_BUILTINS 71 +#define DUK_NUM_ALL_BUILTINS 71 +#if defined(DUK_USE_DOUBLE_LE) +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833]; +#endif /* !DUK_SINGLE_FILE */ +#define DUK_BUILTINS_DATA_LENGTH 3833 +#elif defined(DUK_USE_DOUBLE_BE) +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833]; +#endif /* !DUK_SINGLE_FILE */ +#define DUK_BUILTINS_DATA_LENGTH 3833 +#elif defined(DUK_USE_DOUBLE_ME) +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833]; +#endif /* !DUK_SINGLE_FILE */ +#define DUK_BUILTINS_DATA_LENGTH 3833 +#else +#error invalid endianness defines +#endif +#endif /* DUK_USE_ROM_OBJECTS */ +#endif /* DUK_BUILTINS_H_INCLUDED */ + +/* + * Utilities + */ + +#ifndef DUK_UTIL_H_INCLUDED +#define DUK_UTIL_H_INCLUDED + +#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */ + +#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f]) + +/* + * Endian conversion + */ + +#if defined(DUK_USE_INTEGER_LE) +#define DUK_HTON32(x) DUK_BSWAP32((x)) +#define DUK_NTOH32(x) DUK_BSWAP32((x)) +#define DUK_HTON16(x) DUK_BSWAP16((x)) +#define DUK_NTOH16(x) DUK_BSWAP16((x)) +#elif defined(DUK_USE_INTEGER_BE) +#define DUK_HTON32(x) (x) +#define DUK_NTOH32(x) (x) +#define DUK_HTON16(x) (x) +#define DUK_NTOH16(x) (x) +#else +#error internal error, endianness defines broken +#endif + +/* + * Bitstream decoder + */ + +struct duk_bitdecoder_ctx { + const duk_uint8_t *data; + duk_size_t offset; + duk_size_t length; + duk_uint32_t currval; + duk_small_int_t currbits; +}; + +/* + * Bitstream encoder + */ + +struct duk_bitencoder_ctx { + duk_uint8_t *data; + duk_size_t offset; + duk_size_t length; + duk_uint32_t currval; + duk_small_int_t currbits; + duk_small_int_t truncated; +}; + +/* + * Raw write/read macros for big endian, unaligned basic values. + * Caller ensures there's enough space. The macros update the pointer + * argument automatically on resizes. The idiom seems a bit odd, but + * leads to compact code. + */ + +#define DUK_RAW_WRITE_U8(ptr,val) do { \ + *(ptr)++ = (duk_uint8_t) (val); \ + } while (0) +#define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be(&(ptr), (duk_uint16_t) (val)) +#define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be(&(ptr), (duk_uint32_t) (val)) +#define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be(&(ptr), (duk_double_t) (val)) +#define DUK_RAW_WRITE_XUTF8(ptr,val) do { \ + /* 'ptr' is evaluated both as LHS and RHS. */ \ + duk_uint8_t *duk__ptr; \ + duk_small_int_t duk__len; \ + duk__ptr = (duk_uint8_t *) (ptr); \ + duk__len = duk_unicode_encode_xutf8((duk_ucodepoint_t) (val), duk__ptr); \ + duk__ptr += duk__len; \ + (ptr) = duk__ptr; \ + } while (0) +#define DUK_RAW_WRITE_CESU8(ptr,val) do { \ + /* 'ptr' is evaluated both as LHS and RHS. */ \ + duk_uint8_t *duk__ptr; \ + duk_small_int_t duk__len; \ + duk__ptr = (duk_uint8_t *) (ptr); \ + duk__len = duk_unicode_encode_cesu8((duk_ucodepoint_t) (val), duk__ptr); \ + duk__ptr += duk__len; \ + (ptr) = duk__ptr; \ + } while (0) + +#define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)++)) +#define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be(&(ptr)); +#define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be(&(ptr)); +#define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be(&(ptr)); + +/* + * Buffer writer (dynamic buffer only) + * + * Helper for writing to a dynamic buffer with a concept of a "spare" area + * to reduce resizes. You can ensure there is enough space beforehand and + * then write for a while without further checks, relying on a stable data + * pointer. Spare handling is automatic so call sites only indicate how + * much data they need right now. + * + * There are several ways to write using bufwriter. The best approach + * depends mainly on how much performance matters over code footprint. + * The key issues are (1) ensuring there is space and (2) keeping the + * pointers consistent. Fast code should ensure space for multiple writes + * with one ensure call. Fastest inner loop code can temporarily borrow + * the 'p' pointer but must write it back eventually. + * + * Be careful to ensure all macro arguments (other than static pointers like + * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if + * necessary (if that's not possible, there should be a note near the macro). + * Buffer write arguments often contain arithmetic etc so this is + * particularly important here. + */ + +/* XXX: Migrate bufwriter and other read/write helpers to its own header? */ + +struct duk_bufwriter_ctx { + duk_uint8_t *p; + duk_uint8_t *p_base; + duk_uint8_t *p_limit; + duk_hbuffer_dynamic *buf; +}; + +#define DUK_BW_SPARE_ADD 64 +#define DUK_BW_SPARE_SHIFT 4 /* 2^4 -> 1/16 = 6.25% spare */ + +/* Initialization and finalization (compaction), converting to other types. */ + +#define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \ + duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \ + } while (0) +#define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \ + duk_bw_init((thr), (bw_ctx), (buf)); \ + } while (0) +#define DUK_BW_COMPACT(thr,bw_ctx) do { \ + /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \ + duk_bw_compact((thr), (bw_ctx)); \ + } while (0) +#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \ + duk_push_lstring((duk_context *) (thr), \ + (const char *) (bw_ctx)->p_base, \ + (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ + } while (0) +/* Pointers may be NULL for a while when 'buf' size is zero and before any + * ENSURE calls have been made. Once an ENSURE has been made, the pointers + * are required to be non-NULL so that it's always valid to use memcpy() and + * memmove(), even for zero size. + */ +#define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) \ + DUK_ASSERT_EXPR((bw_ctx) != NULL && \ + (bw_ctx)->buf != NULL && \ + ((DUK_HBUFFER_DYNAMIC_GET_SIZE((bw_ctx)->buf) == 0) || \ + ((bw_ctx)->p != NULL && \ + (bw_ctx)->p_base != NULL && \ + (bw_ctx)->p_limit != NULL && \ + (bw_ctx)->p_limit >= (bw_ctx)->p_base && \ + (bw_ctx)->p >= (bw_ctx)->p_base && \ + (bw_ctx)->p <= (bw_ctx)->p_limit))) +#define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { \ + DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)); \ + } while (0) + +/* Working with the pointer and current size. */ + +#define DUK_BW_GET_PTR(thr,bw_ctx) \ + ((bw_ctx)->p) +#define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \ + (bw_ctx)->p = (ptr); \ + } while (0) +#define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \ + (bw_ctx)->p += (delta); \ + } while (0) +#define DUK_BW_GET_BASEPTR(thr,bw_ctx) \ + ((bw_ctx)->p_base) +#define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \ + ((bw_ctx)->p_limit) +#define DUK_BW_GET_SIZE(thr,bw_ctx) \ + ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)) +#define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \ + DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ + (bw_ctx)->p = (bw_ctx)->p_base + (sz); \ + } while (0) +#define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \ + /* Reset to zero size, keep current limit. */ \ + (bw_ctx)->p = (bw_ctx)->p_base; \ + } while (0) +#define DUK_BW_GET_BUFFER(thr,bw_ctx) \ + ((bw_ctx)->buf) + +/* Ensuring (reserving) space. */ + +#define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \ + duk_size_t duk__sz, duk__space; \ + DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \ + duk__sz = (sz); \ + duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \ + if (duk__space < duk__sz) { \ + (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \ + } \ + } while (0) +/* NOTE: Multiple evaluation of 'ptr' in this macro. */ +/* XXX: Rework to use an always-inline function? */ +#define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \ + (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \ + (ptr) : \ + ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz)))) +#define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \ + DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p) +#define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \ + (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \ + DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz))) +#define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \ + DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \ + } while (0) + +/* Miscellaneous. */ + +#define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \ + (bw_ctx)->p = (ptr); \ + duk_bw_compact((thr), (bw_ctx)); \ + } while (0) + +/* Fast write calls which assume you control the spare beforehand. + * Multibyte write variants exist and use a temporary write pointer + * because byte writes alias with anything: with a stored pointer + * explicit pointer load/stores get generated (e.g. gcc -Os). + */ + +#define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \ + DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \ + *(bw_ctx)->p++ = (duk_uint8_t) (val); \ + } while (0) +#define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \ + duk_uint8_t *duk__p; \ + DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \ + duk__p = (bw_ctx)->p; \ + *duk__p++ = (duk_uint8_t) (val1); \ + *duk__p++ = (duk_uint8_t) (val2); \ + (bw_ctx)->p = duk__p; \ + } while (0) +#define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \ + duk_uint8_t *duk__p; \ + DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \ + duk__p = (bw_ctx)->p; \ + *duk__p++ = (duk_uint8_t) (val1); \ + *duk__p++ = (duk_uint8_t) (val2); \ + *duk__p++ = (duk_uint8_t) (val3); \ + (bw_ctx)->p = duk__p; \ + } while (0) +#define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ + duk_uint8_t *duk__p; \ + DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \ + duk__p = (bw_ctx)->p; \ + *duk__p++ = (duk_uint8_t) (val1); \ + *duk__p++ = (duk_uint8_t) (val2); \ + *duk__p++ = (duk_uint8_t) (val3); \ + *duk__p++ = (duk_uint8_t) (val4); \ + (bw_ctx)->p = duk__p; \ + } while (0) +#define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ + duk_uint8_t *duk__p; \ + DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \ + duk__p = (bw_ctx)->p; \ + *duk__p++ = (duk_uint8_t) (val1); \ + *duk__p++ = (duk_uint8_t) (val2); \ + *duk__p++ = (duk_uint8_t) (val3); \ + *duk__p++ = (duk_uint8_t) (val4); \ + *duk__p++ = (duk_uint8_t) (val5); \ + (bw_ctx)->p = duk__p; \ + } while (0) +#define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ + duk_uint8_t *duk__p; \ + DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \ + duk__p = (bw_ctx)->p; \ + *duk__p++ = (duk_uint8_t) (val1); \ + *duk__p++ = (duk_uint8_t) (val2); \ + *duk__p++ = (duk_uint8_t) (val3); \ + *duk__p++ = (duk_uint8_t) (val4); \ + *duk__p++ = (duk_uint8_t) (val5); \ + *duk__p++ = (duk_uint8_t) (val6); \ + (bw_ctx)->p = duk__p; \ + } while (0) +#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \ + duk_ucodepoint_t duk__cp; \ + duk_small_int_t duk__enc_len; \ + duk__cp = (cp); \ + DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \ + duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \ + (bw_ctx)->p += duk__enc_len; \ + } while (0) +#define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \ + duk_ucodepoint_t duk__cp; \ + duk_small_int_t duk__enc_len; \ + duk__cp = (duk_ucodepoint_t) (cp); \ + DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \ + duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \ + (bw_ctx)->p += duk__enc_len; \ + } while (0) +/* XXX: add temporary duk__p pointer here too; sharing */ +#define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \ + const void *duk__valptr; \ + duk_size_t duk__valsz; \ + duk__valptr = (const void *) (valptr); \ + duk__valsz = (duk_size_t) (valsz); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ + (bw_ctx)->p += duk__valsz; \ + } while (0) +#define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \ + const duk_uint8_t *duk__val; \ + duk_size_t duk__val_len; \ + duk__val = (const duk_uint8_t *) (val); \ + duk__val_len = DUK_STRLEN((const char *) duk__val); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) +#define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \ + duk_size_t duk__val_len; \ + duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) +#define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \ + duk_size_t duk__val_len; \ + duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) +#define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \ + duk_size_t duk__val_len; \ + duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) +#define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ + duk_size_t duk__val_len; \ + duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) + +/* Append bytes from a slice already in the buffer. */ +#define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \ + duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len)) + +/* Insert bytes in the middle of the buffer from an external buffer. */ +#define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \ + duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len)) + +/* Insert bytes in the middle of the buffer from a slice already + * in the buffer. Source offset is interpreted "before" the operation. + */ +#define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \ + duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len)) + +/* Insert a reserved area somewhere in the buffer; caller fills it. + * Evaluates to a (duk_uint_t *) pointing to the start of the reserved + * area for convenience. + */ +#define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \ + duk_bw_insert_raw_area((thr), (bw), (off), (len)) + +/* Remove a slice from inside buffer. */ +#define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \ + duk_bw_remove_raw_slice((thr), (bw), (off), (len)) + +/* Safe write calls which will ensure space first. */ + +#define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \ + DUK_BW_ENSURE((thr), (bw_ctx), 1); \ + DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \ + } while (0) +#define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \ + DUK_BW_ENSURE((thr), (bw_ctx), 2); \ + DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \ + } while (0) +#define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \ + DUK_BW_ENSURE((thr), (bw_ctx), 3); \ + DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \ + } while (0) +#define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ + DUK_BW_ENSURE((thr), (bw_ctx), 4); \ + DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \ + } while (0) +#define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ + DUK_BW_ENSURE((thr), (bw_ctx), 5); \ + DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \ + } while (0) +#define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ + DUK_BW_ENSURE((thr), (bw_ctx), 6); \ + DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \ + } while (0) +#define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \ + DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \ + DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \ + } while (0) +#define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \ + DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \ + DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \ + } while (0) +/* XXX: add temporary duk__p pointer here too; sharing */ +#define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \ + const void *duk__valptr; \ + duk_size_t duk__valsz; \ + duk__valptr = (const void *) (valptr); \ + duk__valsz = (duk_size_t) (valsz); \ + DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ + (bw_ctx)->p += duk__valsz; \ + } while (0) +#define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \ + const duk_uint8_t *duk__val; \ + duk_size_t duk__val_len; \ + duk__val = (const duk_uint8_t *) (val); \ + duk__val_len = DUK_STRLEN((const char *) duk__val); \ + DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) +#define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \ + duk_size_t duk__val_len; \ + duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ + DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) +#define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \ + duk_size_t duk__val_len; \ + duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ + DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) +#define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \ + duk_size_t duk__val_len; \ + duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ + DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) +#define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ + duk_size_t duk__val_len; \ + duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ + DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ + DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + (bw_ctx)->p += duk__val_len; \ + } while (0) + +#define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \ + duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len)) +#define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \ + duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len)) +#define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \ + duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len)) +#define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \ + /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \ + duk_bw_insert_ensure_area((thr), (bw), (off), (len)) +#define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \ + /* No difference between raw/ensure because the buffer shrinks. */ \ + DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len)) + +/* + * Externs and prototypes + */ + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36]; +DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16]; +DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256]; +#if defined(DUK_USE_HEX_FASTPATH) +DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256]; +DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256]; +#endif +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64]; +DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256]; +#endif +#endif /* !DUK_SINGLE_FILE */ + +/* Note: assumes that duk_util_probe_steps size is 32 */ +#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; +#endif /* !DUK_SINGLE_FILE */ +#endif + +#if defined(DUK_USE_STRHASH_DENSE) +DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); +#endif + +#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) +DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size); +#endif + +DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); +DUK_INTERNAL_DECL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); +DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); + +DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits); +DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx); + +DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n); +DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr); + +DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf); +DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size); +DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz); +DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx); +DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); +DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); +DUK_INTERNAL_DECL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); +DUK_INTERNAL_DECL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); +DUK_INTERNAL_DECL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); +DUK_INTERNAL_DECL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); +DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); +DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); +DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); +/* No duk_bw_remove_ensure_slice(), functionality would be identical. */ + +DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p); +DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p); +DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p); +DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val); +DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val); +DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val); + +#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */ +DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len); +#endif + +#endif /* DUK_UTIL_H_INCLUDED */ +/* + * Shared error messages: declarations and macros + * + * Error messages are accessed through macros with fine-grained, explicit + * error message distinctions. Concrete error messages are selected by the + * macros and multiple macros can map to the same concrete string to save + * on code footprint. This allows flexible footprint/verbosity tuning with + * minimal code impact. There are a few limitations to this approach: + * (1) switching between plain messages and format strings doesn't work + * conveniently, and (2) conditional strings are a bit awkward to handle. + * + * Because format strings behave differently in the call site (they need to + * be followed by format arguments), they have a special prefix (DUK_STR_FMT_ + * and duk_str_fmt_). + * + * On some compilers using explicit shared strings is preferable; on others + * it may be better to use straight literals because the compiler will combine + * them anyway, and such strings won't end up unnecessarily in a symbol table. + */ + +#ifndef DUK_ERRMSG_H_INCLUDED +#define DUK_ERRMSG_H_INCLUDED + +#define DUK_STR_INTERNAL_ERROR duk_str_internal_error +#define DUK_STR_INVALID_COUNT duk_str_invalid_count +#define DUK_STR_INVALID_CALL_ARGS duk_str_invalid_call_args +#define DUK_STR_NOT_CONSTRUCTABLE duk_str_not_constructable +#define DUK_STR_NOT_CALLABLE duk_str_not_callable +#define DUK_STR_NOT_EXTENSIBLE duk_str_not_extensible +#define DUK_STR_NOT_WRITABLE duk_str_not_writable +#define DUK_STR_NOT_CONFIGURABLE duk_str_not_configurable + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const char *duk_str_internal_error; +DUK_INTERNAL_DECL const char *duk_str_invalid_count; +DUK_INTERNAL_DECL const char *duk_str_invalid_call_args; +DUK_INTERNAL_DECL const char *duk_str_not_constructable; +DUK_INTERNAL_DECL const char *duk_str_not_callable; +DUK_INTERNAL_DECL const char *duk_str_not_extensible; +DUK_INTERNAL_DECL const char *duk_str_not_writable; +DUK_INTERNAL_DECL const char *duk_str_not_configurable; +#endif /* !DUK_SINGLE_FILE */ + +#define DUK_STR_INVALID_CONTEXT duk_str_invalid_context +#define DUK_STR_INVALID_INDEX duk_str_invalid_call_args +#define DUK_STR_PUSH_BEYOND_ALLOC_STACK duk_str_push_beyond_alloc_stack +#define DUK_STR_NOT_UNDEFINED duk_str_unexpected_type +#define DUK_STR_NOT_NULL duk_str_unexpected_type +#define DUK_STR_NOT_BOOLEAN duk_str_unexpected_type +#define DUK_STR_NOT_NUMBER duk_str_unexpected_type +#define DUK_STR_NOT_STRING duk_str_unexpected_type +#define DUK_STR_NOT_OBJECT duk_str_unexpected_type +#define DUK_STR_NOT_POINTER duk_str_unexpected_type +#define DUK_STR_NOT_BUFFER duk_str_not_buffer /* still in use with verbose messages */ +#define DUK_STR_UNEXPECTED_TYPE duk_str_unexpected_type +#define DUK_STR_NOT_THREAD duk_str_unexpected_type +#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_unexpected_type +#define DUK_STR_NOT_NATIVEFUNCTION duk_str_unexpected_type +#define DUK_STR_NOT_C_FUNCTION duk_str_unexpected_type +#define DUK_STR_NOT_FUNCTION duk_str_unexpected_type +#define DUK_STR_NOT_REGEXP duk_str_unexpected_type +#define DUK_STR_DEFAULTVALUE_COERCE_FAILED duk_str_defaultvalue_coerce_failed +#define DUK_STR_NUMBER_OUTSIDE_RANGE duk_str_number_outside_range +#define DUK_STR_NOT_OBJECT_COERCIBLE duk_str_not_object_coercible +#define DUK_STR_STRING_TOO_LONG duk_str_string_too_long +#define DUK_STR_BUFFER_TOO_LONG duk_str_buffer_too_long +#define DUK_STR_SPRINTF_TOO_LONG duk_str_sprintf_too_long +#define DUK_STR_ALLOC_FAILED duk_str_alloc_failed +#define DUK_STR_POP_TOO_MANY duk_str_pop_too_many +#define DUK_STR_WRONG_BUFFER_TYPE duk_str_wrong_buffer_type +#define DUK_STR_ENCODE_FAILED duk_str_encode_failed +#define DUK_STR_DECODE_FAILED duk_str_decode_failed +#define DUK_STR_NO_SOURCECODE duk_str_no_sourcecode +#define DUK_STR_CONCAT_RESULT_TOO_LONG duk_str_concat_result_too_long +#define DUK_STR_UNIMPLEMENTED duk_str_unimplemented +#define DUK_STR_UNSUPPORTED duk_str_unsupported +#define DUK_STR_ARRAY_LENGTH_OVER_2G duk_str_array_length_over_2g + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const char *duk_str_invalid_context; +DUK_INTERNAL_DECL const char *duk_str_push_beyond_alloc_stack; +DUK_INTERNAL_DECL const char *duk_str_not_buffer; +DUK_INTERNAL_DECL const char *duk_str_unexpected_type; +DUK_INTERNAL_DECL const char *duk_str_defaultvalue_coerce_failed; +DUK_INTERNAL_DECL const char *duk_str_number_outside_range; +DUK_INTERNAL_DECL const char *duk_str_not_object_coercible; +DUK_INTERNAL_DECL const char *duk_str_string_too_long; +DUK_INTERNAL_DECL const char *duk_str_buffer_too_long; +DUK_INTERNAL_DECL const char *duk_str_sprintf_too_long; +DUK_INTERNAL_DECL const char *duk_str_alloc_failed; +DUK_INTERNAL_DECL const char *duk_str_pop_too_many; +DUK_INTERNAL_DECL const char *duk_str_wrong_buffer_type; +DUK_INTERNAL_DECL const char *duk_str_encode_failed; +DUK_INTERNAL_DECL const char *duk_str_decode_failed; +DUK_INTERNAL_DECL const char *duk_str_no_sourcecode; +DUK_INTERNAL_DECL const char *duk_str_concat_result_too_long; +DUK_INTERNAL_DECL const char *duk_str_unimplemented; +DUK_INTERNAL_DECL const char *duk_str_unsupported; +DUK_INTERNAL_DECL const char *duk_str_array_length_over_2g; +#endif /* !DUK_SINGLE_FILE */ + +#define DUK_STR_FMT_PTR duk_str_fmt_ptr +#define DUK_STR_FMT_INVALID_JSON duk_str_fmt_invalid_json +#define DUK_STR_JSONDEC_RECLIMIT duk_str_jsondec_reclimit +#define DUK_STR_JSONENC_RECLIMIT duk_str_jsonenc_reclimit +#define DUK_STR_CYCLIC_INPUT duk_str_cyclic_input + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const char *duk_str_fmt_ptr; +DUK_INTERNAL_DECL const char *duk_str_fmt_invalid_json; +DUK_INTERNAL_DECL const char *duk_str_jsondec_reclimit; +DUK_INTERNAL_DECL const char *duk_str_jsonenc_reclimit; +DUK_INTERNAL_DECL const char *duk_str_cyclic_input; +#endif /* !DUK_SINGLE_FILE */ + +#define DUK_STR_PROXY_REVOKED duk_str_proxy_revoked +#define DUK_STR_INVALID_BASE duk_str_invalid_base +#define DUK_STR_STRICT_CALLER_READ duk_str_strict_caller_read +#define DUK_STR_PROXY_REJECTED duk_str_proxy_rejected +#define DUK_STR_INVALID_ARRAY_LENGTH duk_str_invalid_array_length +#define DUK_STR_ARRAY_LENGTH_WRITE_FAILED duk_str_array_length_write_failed +#define DUK_STR_ARRAY_LENGTH_NOT_WRITABLE duk_str_array_length_not_writable +#define DUK_STR_SETTER_UNDEFINED duk_str_setter_undefined +#define DUK_STR_REDEFINE_VIRT_PROP duk_str_redefine_virt_prop +#define DUK_STR_INVALID_DESCRIPTOR duk_str_invalid_descriptor +#define DUK_STR_PROPERTY_IS_VIRTUAL duk_str_property_is_virtual + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const char *duk_str_proxy_revoked; +DUK_INTERNAL_DECL const char *duk_str_invalid_base; +DUK_INTERNAL_DECL const char *duk_str_strict_caller_read; +DUK_INTERNAL_DECL const char *duk_str_proxy_rejected; +DUK_INTERNAL_DECL const char *duk_str_invalid_array_length; +DUK_INTERNAL_DECL const char *duk_str_array_length_write_failed; +DUK_INTERNAL_DECL const char *duk_str_array_length_not_writable; +DUK_INTERNAL_DECL const char *duk_str_setter_undefined; +DUK_INTERNAL_DECL const char *duk_str_redefine_virt_prop; +DUK_INTERNAL_DECL const char *duk_str_invalid_descriptor; +DUK_INTERNAL_DECL const char *duk_str_property_is_virtual; +#endif /* !DUK_SINGLE_FILE */ + +#define DUK_STR_PARSE_ERROR duk_str_parse_error +#define DUK_STR_DUPLICATE_LABEL duk_str_duplicate_label +#define DUK_STR_INVALID_LABEL duk_str_invalid_label +#define DUK_STR_INVALID_ARRAY_LITERAL duk_str_invalid_array_literal +#define DUK_STR_INVALID_OBJECT_LITERAL duk_str_invalid_object_literal +#define DUK_STR_INVALID_VAR_DECLARATION duk_str_invalid_var_declaration +#define DUK_STR_CANNOT_DELETE_IDENTIFIER duk_str_cannot_delete_identifier +#define DUK_STR_INVALID_EXPRESSION duk_str_invalid_expression +#define DUK_STR_INVALID_LVALUE duk_str_invalid_lvalue +#define DUK_STR_EXPECTED_IDENTIFIER duk_str_expected_identifier +#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED duk_str_empty_expr_not_allowed +#define DUK_STR_INVALID_FOR duk_str_invalid_for +#define DUK_STR_INVALID_SWITCH duk_str_invalid_switch +#define DUK_STR_INVALID_BREAK_CONT_LABEL duk_str_invalid_break_cont_label +#define DUK_STR_INVALID_RETURN duk_str_invalid_return +#define DUK_STR_INVALID_TRY duk_str_invalid_try +#define DUK_STR_INVALID_THROW duk_str_invalid_throw +#define DUK_STR_WITH_IN_STRICT_MODE duk_str_with_in_strict_mode +#define DUK_STR_FUNC_STMT_NOT_ALLOWED duk_str_func_stmt_not_allowed +#define DUK_STR_UNTERMINATED_STMT duk_str_unterminated_stmt +#define DUK_STR_INVALID_ARG_NAME duk_str_invalid_arg_name +#define DUK_STR_INVALID_FUNC_NAME duk_str_invalid_func_name +#define DUK_STR_INVALID_GETSET_NAME duk_str_invalid_getset_name +#define DUK_STR_FUNC_NAME_REQUIRED duk_str_func_name_required + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const char *duk_str_parse_error; +DUK_INTERNAL_DECL const char *duk_str_duplicate_label; +DUK_INTERNAL_DECL const char *duk_str_invalid_label; +DUK_INTERNAL_DECL const char *duk_str_invalid_array_literal; +DUK_INTERNAL_DECL const char *duk_str_invalid_object_literal; +DUK_INTERNAL_DECL const char *duk_str_invalid_var_declaration; +DUK_INTERNAL_DECL const char *duk_str_cannot_delete_identifier; +DUK_INTERNAL_DECL const char *duk_str_invalid_expression; +DUK_INTERNAL_DECL const char *duk_str_invalid_lvalue; +DUK_INTERNAL_DECL const char *duk_str_expected_identifier; +DUK_INTERNAL_DECL const char *duk_str_empty_expr_not_allowed; +DUK_INTERNAL_DECL const char *duk_str_invalid_for; +DUK_INTERNAL_DECL const char *duk_str_invalid_switch; +DUK_INTERNAL_DECL const char *duk_str_invalid_break_cont_label; +DUK_INTERNAL_DECL const char *duk_str_invalid_return; +DUK_INTERNAL_DECL const char *duk_str_invalid_try; +DUK_INTERNAL_DECL const char *duk_str_invalid_throw; +DUK_INTERNAL_DECL const char *duk_str_with_in_strict_mode; +DUK_INTERNAL_DECL const char *duk_str_func_stmt_not_allowed; +DUK_INTERNAL_DECL const char *duk_str_unterminated_stmt; +DUK_INTERNAL_DECL const char *duk_str_invalid_arg_name; +DUK_INTERNAL_DECL const char *duk_str_invalid_func_name; +DUK_INTERNAL_DECL const char *duk_str_invalid_getset_name; +DUK_INTERNAL_DECL const char *duk_str_func_name_required; +#endif /* !DUK_SINGLE_FILE */ + +#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM duk_str_invalid_quantifier_no_atom +#define DUK_STR_INVALID_QUANTIFIER_VALUES duk_str_invalid_quantifier_values +#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES duk_str_quantifier_too_many_copies +#define DUK_STR_UNEXPECTED_CLOSING_PAREN duk_str_unexpected_closing_paren +#define DUK_STR_UNEXPECTED_END_OF_PATTERN duk_str_unexpected_end_of_pattern +#define DUK_STR_UNEXPECTED_REGEXP_TOKEN duk_str_unexpected_regexp_token +#define DUK_STR_INVALID_REGEXP_FLAGS duk_str_invalid_regexp_flags +#define DUK_STR_INVALID_BACKREFS duk_str_invalid_backrefs + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_no_atom; +DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_values; +DUK_INTERNAL_DECL const char *duk_str_quantifier_too_many_copies; +DUK_INTERNAL_DECL const char *duk_str_unexpected_closing_paren; +DUK_INTERNAL_DECL const char *duk_str_unexpected_end_of_pattern; +DUK_INTERNAL_DECL const char *duk_str_unexpected_regexp_token; +DUK_INTERNAL_DECL const char *duk_str_invalid_regexp_flags; +DUK_INTERNAL_DECL const char *duk_str_invalid_backrefs; +#endif /* !DUK_SINGLE_FILE */ + +#define DUK_STR_VALSTACK_LIMIT duk_str_valstack_limit +#define DUK_STR_CALLSTACK_LIMIT duk_str_callstack_limit +#define DUK_STR_CATCHSTACK_LIMIT duk_str_catchstack_limit +#define DUK_STR_PROTOTYPE_CHAIN_LIMIT duk_str_prototype_chain_limit +#define DUK_STR_BOUND_CHAIN_LIMIT duk_str_bound_chain_limit +#define DUK_STR_C_CALLSTACK_LIMIT duk_str_c_callstack_limit +#define DUK_STR_COMPILER_RECURSION_LIMIT duk_str_compiler_recursion_limit +#define DUK_STR_BYTECODE_LIMIT duk_str_bytecode_limit +#define DUK_STR_REG_LIMIT duk_str_reg_limit +#define DUK_STR_TEMP_LIMIT duk_str_temp_limit +#define DUK_STR_CONST_LIMIT duk_str_const_limit +#define DUK_STR_FUNC_LIMIT duk_str_func_limit +#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT duk_str_regexp_compiler_recursion_limit +#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT duk_str_regexp_executor_recursion_limit +#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT duk_str_regexp_executor_step_limit + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const char *duk_str_valstack_limit; +DUK_INTERNAL_DECL const char *duk_str_callstack_limit; +DUK_INTERNAL_DECL const char *duk_str_catchstack_limit; +DUK_INTERNAL_DECL const char *duk_str_prototype_chain_limit; +DUK_INTERNAL_DECL const char *duk_str_bound_chain_limit; +DUK_INTERNAL_DECL const char *duk_str_c_callstack_limit; +DUK_INTERNAL_DECL const char *duk_str_compiler_recursion_limit; +DUK_INTERNAL_DECL const char *duk_str_bytecode_limit; +DUK_INTERNAL_DECL const char *duk_str_reg_limit; +DUK_INTERNAL_DECL const char *duk_str_temp_limit; +DUK_INTERNAL_DECL const char *duk_str_const_limit; +DUK_INTERNAL_DECL const char *duk_str_func_limit; +DUK_INTERNAL_DECL const char *duk_str_regexp_compiler_recursion_limit; +DUK_INTERNAL_DECL const char *duk_str_regexp_executor_recursion_limit; +DUK_INTERNAL_DECL const char *duk_str_regexp_executor_step_limit; +#endif /* !DUK_SINGLE_FILE */ + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const char *duk_str_anon; +#endif /* !DUK_SINGLE_FILE */ + +#endif /* DUK_ERRMSG_H_INCLUDED */ +/* + * Ecmascript bytecode + */ + +#ifndef DUK_JS_BYTECODE_H_INCLUDED +#define DUK_JS_BYTECODE_H_INCLUDED + +/* + * Logical instruction layout + * ========================== + * + * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! + * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! + * +---------------------------------------------------+-----------+ + * ! C ! B ! A ! OP ! + * +---------------------------------------------------+-----------+ + * + * OP (6 bits): opcode (DUK_OP_*), access should be fastest + * A (8 bits): typically a target register number + * B (9 bits): typically first source register/constant number + * C (9 bits): typically second source register/constant number + * + * Some instructions combine BC or ABC together for larger parameter values. + * Signed integers (e.g. jump offsets) are encoded as unsigned, with an opcode + * specific bias. B and C may denote a register or a constant, see + * DUK_BC_ISREG() and DUK_BC_ISCONST(). + * + * Note: macro naming is a bit misleading, e.g. "ABC" in macro name but + * the field layout is logically "CBA". + */ + +typedef duk_uint32_t duk_instr_t; + +#define DUK_DEC_OP(x) ((x) & 0x3fUL) +#define DUK_DEC_A(x) (((x) >> 6) & 0xffUL) +#define DUK_DEC_B(x) (((x) >> 14) & 0x1ffUL) +#define DUK_DEC_C(x) (((x) >> 23) & 0x1ffUL) +#define DUK_DEC_BC(x) (((x) >> 14) & 0x3ffffUL) +#define DUK_DEC_ABC(x) (((x) >> 6) & 0x3ffffffUL) + +#define DUK_ENC_OP(op) ((duk_instr_t) (op)) +#define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \ + (((duk_instr_t) (abc)) << 6) | \ + ((duk_instr_t) (op)) \ + )) +#define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \ + (((duk_instr_t) (bc)) << 14) | \ + (((duk_instr_t) (a)) << 6) | \ + ((duk_instr_t) (op)) \ + )) +#define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \ + (((duk_instr_t) (c)) << 23) | \ + (((duk_instr_t) (b)) << 14) | \ + (((duk_instr_t) (a)) << 6) | \ + ((duk_instr_t) (op)) \ + )) +#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C(op,a,b,0) +#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C(op,a,0,0) + +/* Constants should be signed so that signed arithmetic involving them + * won't cause values to be coerced accidentally to unsigned. + */ +#define DUK_BC_OP_MIN 0 +#define DUK_BC_OP_MAX 0x3fL +#define DUK_BC_A_MIN 0 +#define DUK_BC_A_MAX 0xffL +#define DUK_BC_B_MIN 0 +#define DUK_BC_B_MAX 0x1ffL +#define DUK_BC_C_MIN 0 +#define DUK_BC_C_MAX 0x1ffL +#define DUK_BC_BC_MIN 0 +#define DUK_BC_BC_MAX 0x3ffffL +#define DUK_BC_ABC_MIN 0 +#define DUK_BC_ABC_MAX 0x3ffffffL +#define DUK_BC_EXTRAOP_MIN DUK_BC_A_MIN +#define DUK_BC_EXTRAOP_MAX DUK_BC_A_MAX + +#define DUK_OP_LDREG 0 +#define DUK_OP_STREG 1 +#define DUK_OP_LDCONST 2 +#define DUK_OP_LDINT 3 +#define DUK_OP_LDINTX 4 +#define DUK_OP_MPUTOBJ 5 +#define DUK_OP_MPUTOBJI 6 +#define DUK_OP_MPUTARR 7 +#define DUK_OP_MPUTARRI 8 +#define DUK_OP_NEW 9 +#define DUK_OP_NEWI 10 +#define DUK_OP_REGEXP 11 +#define DUK_OP_CSREG 12 +#define DUK_OP_CSREGI 13 +#define DUK_OP_GETVAR 14 +#define DUK_OP_PUTVAR 15 +#define DUK_OP_DECLVAR 16 +#define DUK_OP_DELVAR 17 +#define DUK_OP_CSVAR 18 +#define DUK_OP_CSVARI 19 +#define DUK_OP_CLOSURE 20 +#define DUK_OP_GETPROP 21 +#define DUK_OP_PUTPROP 22 +#define DUK_OP_DELPROP 23 +#define DUK_OP_CSPROP 24 +#define DUK_OP_CSPROPI 25 +#define DUK_OP_ADD 26 +#define DUK_OP_SUB 27 +#define DUK_OP_MUL 28 +#define DUK_OP_DIV 29 +#define DUK_OP_MOD 30 +#define DUK_OP_BAND 31 +#define DUK_OP_BOR 32 +#define DUK_OP_BXOR 33 +#define DUK_OP_BASL 34 +#define DUK_OP_BLSR 35 +#define DUK_OP_BASR 36 +#define DUK_OP_EQ 37 +#define DUK_OP_NEQ 38 +#define DUK_OP_SEQ 39 +#define DUK_OP_SNEQ 40 +#define DUK_OP_GT 41 +#define DUK_OP_GE 42 +#define DUK_OP_LT 43 +#define DUK_OP_LE 44 +#define DUK_OP_IF 45 +#define DUK_OP_JUMP 46 +#define DUK_OP_RETURN 47 +#define DUK_OP_CALL 48 +#define DUK_OP_CALLI 49 +#define DUK_OP_TRYCATCH 50 +#define DUK_OP_EXTRA 51 +#define DUK_OP_PREINCR 52 /* pre/post opcode values have constraints, */ +#define DUK_OP_PREDECR 53 /* see duk_js_executor.c */ +#define DUK_OP_POSTINCR 54 +#define DUK_OP_POSTDECR 55 +#define DUK_OP_PREINCV 56 +#define DUK_OP_PREDECV 57 +#define DUK_OP_POSTINCV 58 +#define DUK_OP_POSTDECV 59 +#define DUK_OP_PREINCP 60 +#define DUK_OP_PREDECP 61 +#define DUK_OP_POSTINCP 62 +#define DUK_OP_POSTDECP 63 +#define DUK_OP_NONE 64 /* dummy value used as marker */ + +/* DUK_OP_EXTRA, sub-operation in A */ +#define DUK_EXTRAOP_NOP 0 +#define DUK_EXTRAOP_INVALID 1 +#define DUK_EXTRAOP_LDTHIS 2 +#define DUK_EXTRAOP_LDUNDEF 3 +#define DUK_EXTRAOP_LDNULL 4 +#define DUK_EXTRAOP_LDTRUE 5 +#define DUK_EXTRAOP_LDFALSE 6 +#define DUK_EXTRAOP_NEWOBJ 7 +#define DUK_EXTRAOP_NEWARR 8 +#define DUK_EXTRAOP_SETALEN 9 +#define DUK_EXTRAOP_TYPEOF 10 +#define DUK_EXTRAOP_TYPEOFID 11 +#define DUK_EXTRAOP_INITENUM 12 +#define DUK_EXTRAOP_NEXTENUM 13 +#define DUK_EXTRAOP_INITSET 14 +#define DUK_EXTRAOP_INITSETI 15 +#define DUK_EXTRAOP_INITGET 16 +#define DUK_EXTRAOP_INITGETI 17 +#define DUK_EXTRAOP_ENDTRY 18 +#define DUK_EXTRAOP_ENDCATCH 19 +#define DUK_EXTRAOP_ENDFIN 20 +#define DUK_EXTRAOP_THROW 21 +#define DUK_EXTRAOP_INVLHS 22 +#define DUK_EXTRAOP_UNM 23 +#define DUK_EXTRAOP_UNP 24 +#define DUK_EXTRAOP_DEBUGGER 25 +#define DUK_EXTRAOP_BREAK 26 +#define DUK_EXTRAOP_CONTINUE 27 +#define DUK_EXTRAOP_BNOT 28 +#define DUK_EXTRAOP_LNOT 29 +#define DUK_EXTRAOP_INSTOF 30 +#define DUK_EXTRAOP_IN 31 +#define DUK_EXTRAOP_LABEL 32 +#define DUK_EXTRAOP_ENDLABEL 33 + +/* DUK_OP_CALL flags in A */ +#define DUK_BC_CALL_FLAG_TAILCALL (1 << 0) +#define DUK_BC_CALL_FLAG_EVALCALL (1 << 1) + +/* DUK_OP_TRYCATCH flags in A */ +#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1 << 0) +#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1 << 1) +#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1 << 2) +#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3) + +/* DUK_OP_RETURN flags in A */ +#define DUK_BC_RETURN_FLAG_HAVE_RETVAL (1 << 0) + +/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */ +#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */ +#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */ + +/* misc constants and helper macros */ +#define DUK_BC_REGLIMIT 256 /* if B/C is >= this value, refers to a const */ +#define DUK_BC_ISREG(x) ((x) < DUK_BC_REGLIMIT) +#define DUK_BC_ISCONST(x) ((x) >= DUK_BC_REGLIMIT) +#define DUK_BC_LDINT_BIAS (1L << 17) +#define DUK_BC_LDINTX_SHIFT 18 +#define DUK_BC_JUMP_BIAS (1L << 25) + +#endif /* DUK_JS_BYTECODE_H_INCLUDED */ +/* + * Lexer defines. + */ + +#ifndef DUK_LEXER_H_INCLUDED +#define DUK_LEXER_H_INCLUDED + +typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct); + +/* + * A token is interpreted as any possible production of InputElementDiv + * and InputElementRegExp, see E5 Section 7 in its entirety. Note that + * the E5 "Token" production does not cover all actual tokens of the + * language (which is explicitly stated in the specification, Section 7.5). + * Null and boolean literals are defined as part of both ReservedWord + * (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions. Here, + * null and boolean values have literal tokens, and are not reserved + * words. + * + * Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER. + * The number tokens always have a non-negative value. The unary minus + * operator in "-1.0" is optimized during compilation to yield a single + * negative constant. + * + * Token numbering is free except that reserved words are required to be + * in a continuous range and in a particular order. See genstrings.py. + */ + +#define DUK_LEXER_INITCTX(ctx) duk_lexer_initctx((ctx)) + +#define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt)) + +#define DUK_LEXER_GETPOINT(ctx,pt) do { (pt)->offset = (ctx)->window[0].offset; \ + (pt)->line = (ctx)->window[0].line; } while (0) + +/* currently 6 characters of lookup are actually needed (duk_lexer.c) */ +#define DUK_LEXER_WINDOW_SIZE 6 +#if defined(DUK_USE_LEXER_SLIDING_WINDOW) +#define DUK_LEXER_BUFFER_SIZE 64 +#endif + +#define DUK_TOK_MINVAL 0 + +/* returned after EOF (infinite amount) */ +#define DUK_TOK_EOF 0 + +/* identifier names (E5 Section 7.6) */ +#define DUK_TOK_IDENTIFIER 1 + +/* reserved words: keywords */ +#define DUK_TOK_START_RESERVED 2 +#define DUK_TOK_BREAK 2 +#define DUK_TOK_CASE 3 +#define DUK_TOK_CATCH 4 +#define DUK_TOK_CONTINUE 5 +#define DUK_TOK_DEBUGGER 6 +#define DUK_TOK_DEFAULT 7 +#define DUK_TOK_DELETE 8 +#define DUK_TOK_DO 9 +#define DUK_TOK_ELSE 10 +#define DUK_TOK_FINALLY 11 +#define DUK_TOK_FOR 12 +#define DUK_TOK_FUNCTION 13 +#define DUK_TOK_IF 14 +#define DUK_TOK_IN 15 +#define DUK_TOK_INSTANCEOF 16 +#define DUK_TOK_NEW 17 +#define DUK_TOK_RETURN 18 +#define DUK_TOK_SWITCH 19 +#define DUK_TOK_THIS 20 +#define DUK_TOK_THROW 21 +#define DUK_TOK_TRY 22 +#define DUK_TOK_TYPEOF 23 +#define DUK_TOK_VAR 24 +#define DUK_TOK_CONST 25 +#define DUK_TOK_VOID 26 +#define DUK_TOK_WHILE 27 +#define DUK_TOK_WITH 28 + +/* reserved words: future reserved words */ +#define DUK_TOK_CLASS 29 +#define DUK_TOK_ENUM 30 +#define DUK_TOK_EXPORT 31 +#define DUK_TOK_EXTENDS 32 +#define DUK_TOK_IMPORT 33 +#define DUK_TOK_SUPER 34 + +/* "null", "true", and "false" are always reserved words. + * Note that "get" and "set" are not! + */ +#define DUK_TOK_NULL 35 +#define DUK_TOK_TRUE 36 +#define DUK_TOK_FALSE 37 + +/* reserved words: additional future reserved words in strict mode */ +#define DUK_TOK_START_STRICT_RESERVED 38 /* inclusive */ +#define DUK_TOK_IMPLEMENTS 38 +#define DUK_TOK_INTERFACE 39 +#define DUK_TOK_LET 40 +#define DUK_TOK_PACKAGE 41 +#define DUK_TOK_PRIVATE 42 +#define DUK_TOK_PROTECTED 43 +#define DUK_TOK_PUBLIC 44 +#define DUK_TOK_STATIC 45 +#define DUK_TOK_YIELD 46 + +#define DUK_TOK_END_RESERVED 47 /* exclusive */ + +/* "get" and "set" are tokens but NOT ReservedWords. They are currently + * parsed and identifiers and these defines are actually now unused. + */ +#define DUK_TOK_GET 47 +#define DUK_TOK_SET 48 + +/* punctuators (unlike the spec, also includes "/" and "/=") */ +#define DUK_TOK_LCURLY 49 +#define DUK_TOK_RCURLY 50 +#define DUK_TOK_LBRACKET 51 +#define DUK_TOK_RBRACKET 52 +#define DUK_TOK_LPAREN 53 +#define DUK_TOK_RPAREN 54 +#define DUK_TOK_PERIOD 55 +#define DUK_TOK_SEMICOLON 56 +#define DUK_TOK_COMMA 57 +#define DUK_TOK_LT 58 +#define DUK_TOK_GT 59 +#define DUK_TOK_LE 60 +#define DUK_TOK_GE 61 +#define DUK_TOK_EQ 62 +#define DUK_TOK_NEQ 63 +#define DUK_TOK_SEQ 64 +#define DUK_TOK_SNEQ 65 +#define DUK_TOK_ADD 66 +#define DUK_TOK_SUB 67 +#define DUK_TOK_MUL 68 +#define DUK_TOK_DIV 69 +#define DUK_TOK_MOD 70 +#define DUK_TOK_INCREMENT 71 +#define DUK_TOK_DECREMENT 72 +#define DUK_TOK_ALSHIFT 73 /* named "arithmetic" because result is signed */ +#define DUK_TOK_ARSHIFT 74 +#define DUK_TOK_RSHIFT 75 +#define DUK_TOK_BAND 76 +#define DUK_TOK_BOR 77 +#define DUK_TOK_BXOR 78 +#define DUK_TOK_LNOT 79 +#define DUK_TOK_BNOT 80 +#define DUK_TOK_LAND 81 +#define DUK_TOK_LOR 82 +#define DUK_TOK_QUESTION 83 +#define DUK_TOK_COLON 84 +#define DUK_TOK_EQUALSIGN 85 +#define DUK_TOK_ADD_EQ 86 +#define DUK_TOK_SUB_EQ 87 +#define DUK_TOK_MUL_EQ 88 +#define DUK_TOK_DIV_EQ 89 +#define DUK_TOK_MOD_EQ 90 +#define DUK_TOK_ALSHIFT_EQ 91 +#define DUK_TOK_ARSHIFT_EQ 92 +#define DUK_TOK_RSHIFT_EQ 93 +#define DUK_TOK_BAND_EQ 94 +#define DUK_TOK_BOR_EQ 95 +#define DUK_TOK_BXOR_EQ 96 + +/* literals (E5 Section 7.8), except null, true, false, which are treated + * like reserved words (above). + */ +#define DUK_TOK_NUMBER 97 +#define DUK_TOK_STRING 98 +#define DUK_TOK_REGEXP 99 + +#define DUK_TOK_MAXVAL 99 /* inclusive */ + +/* Convert heap string index to a token (reserved words) */ +#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED) + +/* Sanity check */ +#if (DUK_TOK_MAXVAL > 255) +#error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits +#endif + +/* Sanity checks for string and token defines */ +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_NULL) != DUK_TOK_NULL) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC) +#error mismatch in token defines +#endif +#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD) +#error mismatch in token defines +#endif + +/* Regexp tokens */ +#define DUK_RETOK_EOF 0 +#define DUK_RETOK_DISJUNCTION 1 +#define DUK_RETOK_QUANTIFIER 2 +#define DUK_RETOK_ASSERT_START 3 +#define DUK_RETOK_ASSERT_END 4 +#define DUK_RETOK_ASSERT_WORD_BOUNDARY 5 +#define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY 6 +#define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD 7 +#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8 +#define DUK_RETOK_ATOM_PERIOD 9 +#define DUK_RETOK_ATOM_CHAR 10 +#define DUK_RETOK_ATOM_DIGIT 11 +#define DUK_RETOK_ATOM_NOT_DIGIT 12 +#define DUK_RETOK_ATOM_WHITE 13 +#define DUK_RETOK_ATOM_NOT_WHITE 14 +#define DUK_RETOK_ATOM_WORD_CHAR 15 +#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16 +#define DUK_RETOK_ATOM_BACKREFERENCE 17 +#define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18 +#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19 +#define DUK_RETOK_ATOM_START_CHARCLASS 20 +#define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED 21 +#define DUK_RETOK_ATOM_END_GROUP 22 + +/* Constants for duk_lexer_ctx.buf. */ +#define DUK_LEXER_TEMP_BUF_LIMIT 256 + +/* A token value. Can be memcpy()'d, but note that slot1/slot2 values are on the valstack. + * Some fields (like num, str1, str2) are only valid for specific token types and may have + * stale values otherwise. + */ +struct duk_token { + duk_small_int_t t; /* token type (with reserved word identification) */ + duk_small_int_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */ + duk_double_t num; /* numeric value of token */ + duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */ + duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */ + duk_size_t start_offset; /* start byte offset of token in lexer input */ + duk_int_t start_line; /* start line of token (first char) */ + duk_int_t num_escapes; /* number of escapes and line continuations (for directive prologue) */ + duk_bool_t lineterm; /* token was preceded by a lineterm */ + duk_bool_t allow_auto_semi; /* token allows automatic semicolon insertion (eof or preceded by newline) */ +}; + +#define DUK_RE_QUANTIFIER_INFINITE ((duk_uint32_t) 0xffffffffUL) + +/* A regexp token value. */ +struct duk_re_token { + duk_small_int_t t; /* token type */ + duk_small_int_t greedy; + duk_uint_fast32_t num; /* numeric value (character, count) */ + duk_uint_fast32_t qmin; + duk_uint_fast32_t qmax; +}; + +/* A structure for 'snapshotting' a point for rewinding */ +struct duk_lexer_point { + duk_size_t offset; + duk_int_t line; +}; + +/* Lexer codepoint with additional info like offset/line number */ +struct duk_lexer_codepoint { + duk_codepoint_t codepoint; + duk_size_t offset; + duk_int_t line; +}; + +/* Lexer context. Same context is used for Ecmascript and Regexp parsing. */ +struct duk_lexer_ctx { +#if defined(DUK_USE_LEXER_SLIDING_WINDOW) + duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */ + duk_lexer_codepoint buffer[DUK_LEXER_BUFFER_SIZE]; +#else + duk_lexer_codepoint window[DUK_LEXER_WINDOW_SIZE]; /* unicode code points, window[0] is always next */ +#endif + + duk_hthread *thr; /* thread; minimizes argument passing */ + + const duk_uint8_t *input; /* input string (may be a user pointer) */ + duk_size_t input_length; /* input byte length */ + duk_size_t input_offset; /* input offset for window leading edge (not window[0]) */ + duk_int_t input_line; /* input linenumber at input_offset (not window[0]), init to 1 */ + + duk_idx_t slot1_idx; /* valstack slot for 1st token value */ + duk_idx_t slot2_idx; /* valstack slot for 2nd token value */ + duk_idx_t buf_idx; /* valstack slot for temp buffer */ + duk_hbuffer_dynamic *buf; /* temp accumulation buffer */ + duk_bufwriter_ctx bw; /* bufwriter for temp accumulation */ + + duk_int_t token_count; /* number of tokens parsed */ + duk_int_t token_limit; /* maximum token count before error (sanity backstop) */ +}; + +/* + * Prototypes + */ + +DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx); + +DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt); + +DUK_INTERNAL_DECL +void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx, + duk_token *out_token, + duk_bool_t strict_mode, + duk_bool_t regexp_mode); +#ifdef DUK_USE_REGEXP_SUPPORT +DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token); +DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata); +#endif /* DUK_USE_REGEXP_SUPPORT */ + +#endif /* DUK_LEXER_H_INCLUDED */ +/* + * Ecmascript compiler. + */ + +#ifndef DUK_JS_COMPILER_H_INCLUDED +#define DUK_JS_COMPILER_H_INCLUDED + +/* ecmascript compiler limits */ +#define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */ + +/* maximum loopcount for peephole optimization */ +#define DUK_COMPILER_PEEPHOLE_MAXITER 3 + +/* maximum bytecode length in instructions */ +#define DUK_COMPILER_MAX_BYTECODE_LENGTH (256L * 1024L * 1024L) /* 1 GB */ + +/* + * Compiler intermediate values + * + * Intermediate values describe either plain values (e.g. strings or + * numbers) or binary operations which have not yet been coerced into + * either a left-hand-side or right-hand-side role (e.g. object property). + */ + +#define DUK_IVAL_NONE 0 /* no value */ +#define DUK_IVAL_PLAIN 1 /* register, constant, or value */ +#define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */ +#define DUK_IVAL_ARITH_EXTRAOP 3 /* binary arithmetic using extraops; DUK_EXTRAOP_INSTOF etc */ +#define DUK_IVAL_PROP 4 /* property access */ +#define DUK_IVAL_VAR 5 /* variable access */ + +#define DUK_ISPEC_NONE 0 /* no value */ +#define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */ +#define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */ + +/* bit mask which indicates that a regconst is a constant instead of a register */ +#define DUK_JS_CONST_MARKER 0x80000000UL + +/* type to represent a reg/const reference during compilation */ +typedef duk_uint32_t duk_regconst_t; + +/* type to represent a straight register reference, with <0 indicating none */ +typedef duk_int32_t duk_reg_t; + +typedef struct { + duk_small_uint_t t; /* DUK_ISPEC_XXX */ + duk_regconst_t regconst; + duk_idx_t valstack_idx; /* always set; points to a reserved valstack slot */ +} duk_ispec; + +typedef struct { + /* + * PLAIN: x1 + * ARITH: x1 x2 + * PROP: x1.x2 + * VAR: x1 (name) + */ + + /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */ + duk_small_uint_t t; /* DUK_IVAL_XXX */ + duk_small_uint_t op; /* bytecode opcode (or extraop) for binary ops */ + duk_ispec x1; + duk_ispec x2; +} duk_ivalue; + +/* + * Bytecode instruction representation during compilation + * + * Contains the actual instruction and (optionally) debug info. + */ + +struct duk_compiler_instr { + duk_instr_t ins; +#if defined(DUK_USE_PC2LINE) + duk_uint32_t line; +#endif +}; + +/* + * Compiler state + */ + +#define DUK_LABEL_FLAG_ALLOW_BREAK (1 << 0) +#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1 << 1) + +#define DUK_DECL_TYPE_VAR 0 +#define DUK_DECL_TYPE_FUNC 1 + +/* XXX: optimize to 16 bytes */ +typedef struct { + duk_small_uint_t flags; + duk_int_t label_id; /* numeric label_id (-1 reserved as marker) */ + duk_hstring *h_label; /* borrowed label name */ + duk_int_t catch_depth; /* catch depth at point of definition */ + duk_int_t pc_label; /* pc of label statement: + * pc+1: break jump site + * pc+2: continue jump site + */ + + /* Fast jumps (which avoid longjmp) jump directly to the jump sites + * which are always known even while the iteration/switch statement + * is still being parsed. A final peephole pass "straightens out" + * the jumps. + */ +} duk_labelinfo; + +/* Compiling state of one function, eventually converted to duk_hcompiledfunction */ +struct duk_compiler_func { + /* These pointers are at the start of the struct so that they pack + * nicely. Mixing pointers and integer values is bad on some + * platforms (e.g. if int is 32 bits and pointers are 64 bits). + */ + + duk_bufwriter_ctx bw_code; /* bufwriter for code */ + + duk_hstring *h_name; /* function name (borrowed reference), ends up in _name */ + /* h_code: held in bw_code */ + duk_hobject *h_consts; /* array */ + duk_hobject *h_funcs; /* array of function templates: [func1, offset1, line1, func2, offset2, line2] + * offset/line points to closing brace to allow skipping on pass 2 + */ + duk_hobject *h_decls; /* array of declarations: [ name1, val1, name2, val2, ... ] + * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars) + * record function and variable declarations in pass 1 + */ + duk_hobject *h_labelnames; /* array of active label names */ + duk_hbuffer_dynamic *h_labelinfos; /* C array of duk_labelinfo */ + duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */ + duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */ + + /* value stack indices for tracking objects */ + /* code_idx: not needed */ + duk_idx_t consts_idx; + duk_idx_t funcs_idx; + duk_idx_t decls_idx; + duk_idx_t labelnames_idx; + duk_idx_t labelinfos_idx; + duk_idx_t argnames_idx; + duk_idx_t varmap_idx; + + /* temp reg handling */ + duk_reg_t temp_first; /* first register that is a temporary (below: variables) */ + duk_reg_t temp_next; /* next temporary register to allocate */ + duk_reg_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */ + + /* shuffle registers if large number of regs/consts */ + duk_reg_t shuffle1; + duk_reg_t shuffle2; + duk_reg_t shuffle3; + + /* stats for current expression being parsed */ + duk_int_t nud_count; + duk_int_t led_count; + duk_int_t paren_level; /* parenthesis count, 0 = top level */ + duk_bool_t expr_lhs; /* expression is left-hand-side compatible */ + duk_bool_t allow_in; /* current paren level allows 'in' token */ + + /* misc */ + duk_int_t stmt_next; /* statement id allocation (running counter) */ + duk_int_t label_next; /* label id allocation (running counter) */ + duk_int_t catch_depth; /* catch stack depth */ + duk_int_t with_depth; /* with stack depth (affects identifier lookups) */ + duk_int_t fnum_next; /* inner function numbering */ + duk_int_t num_formals; /* number of formal arguments */ + duk_reg_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */ +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_int_t min_line; /* XXX: typing (duk_hcompiledfunction has duk_uint32_t) */ + duk_int_t max_line; +#endif + + /* status booleans */ + duk_bool_t is_function; /* is an actual function (not global/eval code) */ + duk_bool_t is_eval; /* is eval code */ + duk_bool_t is_global; /* is global code */ + duk_bool_t is_setget; /* is a setter/getter */ + duk_bool_t is_decl; /* is a function declaration (as opposed to function expression) */ + duk_bool_t is_strict; /* function is strict */ + duk_bool_t is_notail; /* function must not be tail called */ + duk_bool_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */ + duk_bool_t in_scanning; /* parsing in "scanning" phase (first pass) */ + duk_bool_t may_direct_eval; /* function may call direct eval */ + duk_bool_t id_access_arguments; /* function refers to 'arguments' identifier */ + duk_bool_t id_access_slow; /* function makes one or more slow path accesses */ + duk_bool_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */ + duk_bool_t needs_shuffle; /* function needs shuffle registers */ + duk_bool_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */ +}; + +struct duk_compiler_ctx { + duk_hthread *thr; + + /* filename being compiled (ends up in functions' '_filename' property) */ + duk_hstring *h_filename; /* borrowed reference */ + + /* lexing (tokenization) state (contains two valstack slot indices) */ + duk_lexer_ctx lex; + + /* current and previous token for parsing */ + duk_token prev_token; + duk_token curr_token; + duk_idx_t tok11_idx; /* curr_token slot1 (matches 'lex' slot1_idx) */ + duk_idx_t tok12_idx; /* curr_token slot2 (matches 'lex' slot2_idx) */ + duk_idx_t tok21_idx; /* prev_token slot1 */ + duk_idx_t tok22_idx; /* prev_token slot2 */ + + /* recursion limit */ + duk_int_t recursion_depth; + duk_int_t recursion_limit; + + /* code emission temporary */ + duk_int_t emit_jumpslot_pc; + + /* current function being compiled (embedded instead of pointer for more compact access) */ + duk_compiler_func curr_func; +}; + +/* + * Prototypes + */ + +#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */ +#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */ +#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */ + +DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags); + +#endif /* DUK_JS_COMPILER_H_INCLUDED */ +/* + * Regular expression structs, constants, and bytecode defines. + */ + +#ifndef DUK_REGEXP_H_INCLUDED +#define DUK_REGEXP_H_INCLUDED + +/* maximum bytecode copies for {n,m} quantifiers */ +#define DUK_RE_MAX_ATOM_COPIES 1000 + +/* regexp compilation limits */ +#define DUK_RE_COMPILE_TOKEN_LIMIT 100000000L /* 1e8 */ + +/* regexp execution limits */ +#define DUK_RE_EXECUTE_STEPS_LIMIT 1000000000L /* 1e9 */ + +/* regexp opcodes */ +#define DUK_REOP_MATCH 1 +#define DUK_REOP_CHAR 2 +#define DUK_REOP_PERIOD 3 +#define DUK_REOP_RANGES 4 +#define DUK_REOP_INVRANGES 5 +#define DUK_REOP_JUMP 6 +#define DUK_REOP_SPLIT1 7 +#define DUK_REOP_SPLIT2 8 +#define DUK_REOP_SQMINIMAL 9 +#define DUK_REOP_SQGREEDY 10 +#define DUK_REOP_SAVE 11 +#define DUK_REOP_WIPERANGE 12 +#define DUK_REOP_LOOKPOS 13 +#define DUK_REOP_LOOKNEG 14 +#define DUK_REOP_BACKREFERENCE 15 +#define DUK_REOP_ASSERT_START 16 +#define DUK_REOP_ASSERT_END 17 +#define DUK_REOP_ASSERT_WORD_BOUNDARY 18 +#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19 + +/* flags */ +#define DUK_RE_FLAG_GLOBAL (1 << 0) +#define DUK_RE_FLAG_IGNORE_CASE (1 << 1) +#define DUK_RE_FLAG_MULTILINE (1 << 2) + +struct duk_re_matcher_ctx { + duk_hthread *thr; + + duk_uint32_t re_flags; + const duk_uint8_t *input; + const duk_uint8_t *input_end; + const duk_uint8_t *bytecode; + const duk_uint8_t *bytecode_end; + const duk_uint8_t **saved; /* allocated from valstack (fixed buffer) */ + duk_uint32_t nsaved; + duk_uint32_t recursion_depth; + duk_uint32_t recursion_limit; + duk_uint32_t steps_count; + duk_uint32_t steps_limit; +}; + +struct duk_re_compiler_ctx { + duk_hthread *thr; + + duk_uint32_t re_flags; + duk_lexer_ctx lex; + duk_re_token curr_token; + duk_bufwriter_ctx bw; + duk_uint32_t captures; /* highest capture number emitted so far (used as: ++captures) */ + duk_uint32_t highest_backref; + duk_uint32_t recursion_depth; + duk_uint32_t recursion_limit; + duk_uint32_t nranges; /* internal temporary value, used for char classes */ +}; + +/* + * Prototypes + */ + +DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */ + +#endif /* DUK_REGEXP_H_INCLUDED */ +/* + * Heap header definition and assorted macros, including ref counting. + * Access all fields through the accessor macros. + */ + +#ifndef DUK_HEAPHDR_H_INCLUDED +#define DUK_HEAPHDR_H_INCLUDED + +/* + * Common heap header + * + * All heap objects share the same flags and refcount fields. Objects other + * than strings also need to have a single or double linked list pointers + * for insertion into the "heap allocated" list. Strings are held in the + * heap-wide string table so they don't need link pointers. + * + * Technically, 'h_refcount' must be wide enough to guarantee that it cannot + * wrap (otherwise objects might be freed incorrectly after wrapping). This + * means essentially that the refcount field must be as wide as data pointers. + * On 64-bit platforms this means that the refcount needs to be 64 bits even + * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on + * this might be reasonable in the future. + * + * Heap header size on 32-bit platforms: 8 bytes without reference counting, + * 16 bytes with reference counting. + */ + +struct duk_heaphdr { + duk_uint32_t h_flags; + +#if defined(DUK_USE_REFERENCE_COUNTING) +#if defined(DUK_USE_REFCOUNT16) + duk_uint16_t h_refcount16; +#else + duk_size_t h_refcount; +#endif +#endif + +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t h_next16; +#else + duk_heaphdr *h_next; +#endif + +#if defined(DUK_USE_DOUBLE_LINKED_HEAP) + /* refcounting requires direct heap frees, which in turn requires a dual linked heap */ +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t h_prev16; +#else + duk_heaphdr *h_prev; +#endif +#endif + + /* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the + * struct won't align nicely to 4 bytes. This 16-bit extra field + * is added to make the alignment clean; the field can be used by + * heap objects when 16-bit packing is used. This field is now + * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be + * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP; + * this only matter to low memory environments anyway. + */ +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t h_extra16; +#endif +}; + +struct duk_heaphdr_string { + /* 16 bits would be enough for shared heaphdr flags and duk_hstring + * flags. The initial parts of duk_heaphdr_string and duk_heaphdr + * must match so changing the flags field size here would be quite + * awkward. However, to minimize struct size, we can pack at least + * 16 bits of duk_hstring data into the flags field. + */ + duk_uint32_t h_flags; + +#if defined(DUK_USE_REFERENCE_COUNTING) +#if defined(DUK_USE_REFCOUNT16) + duk_uint16_t h_refcount16; + duk_uint16_t h_strextra16; /* round out to 8 bytes */ +#else + duk_size_t h_refcount; +#endif +#endif +}; + +#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL +#define DUK_HEAPHDR_FLAGS_FLAG_MASK (~DUK_HEAPHDR_FLAGS_TYPE_MASK) + + /* 2 bits for heap type */ +#define DUK_HEAPHDR_FLAGS_HEAP_START 2 /* 5 heap flags */ +#define DUK_HEAPHDR_FLAGS_USER_START 7 /* 25 user flags */ + +#define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_HEAP_START + (n)) +#define DUK_HEAPHDR_USER_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_USER_START + (n)) +#define DUK_HEAPHDR_HEAP_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n))) +#define DUK_HEAPHDR_USER_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n))) + +#define DUK_HEAPHDR_FLAG_REACHABLE DUK_HEAPHDR_HEAP_FLAG(0) /* mark-and-sweep: reachable */ +#define DUK_HEAPHDR_FLAG_TEMPROOT DUK_HEAPHDR_HEAP_FLAG(1) /* mark-and-sweep: children not processed */ +#define DUK_HEAPHDR_FLAG_FINALIZABLE DUK_HEAPHDR_HEAP_FLAG(2) /* mark-and-sweep: finalizable (on current pass) */ +#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */ +#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */ + +#define DUK_HTYPE_MIN 1 +#define DUK_HTYPE_STRING 1 +#define DUK_HTYPE_OBJECT 2 +#define DUK_HTYPE_BUFFER 3 +#define DUK_HTYPE_MAX 3 + +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HEAPHDR_GET_NEXT(heap,h) \ + ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16)) +#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \ + (h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \ + } while (0) +#else +#define DUK_HEAPHDR_GET_NEXT(heap,h) ((h)->h_next) +#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \ + (h)->h_next = (val); \ + } while (0) +#endif + +#if defined(DUK_USE_DOUBLE_LINKED_HEAP) +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HEAPHDR_GET_PREV(heap,h) \ + ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16)) +#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \ + (h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \ + } while (0) +#else +#define DUK_HEAPHDR_GET_PREV(heap,h) ((h)->h_prev) +#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \ + (h)->h_prev = (val); \ + } while (0) +#endif +#endif + +#if defined(DUK_USE_REFERENCE_COUNTING) +#if defined(DUK_USE_REFCOUNT16) +#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16) +#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \ + (h)->h_refcount16 = (val); \ + } while (0) +#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */ +#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */ +#else +#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount) +#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \ + (h)->h_refcount = (val); \ + } while (0) +#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */ +#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */ +#endif +#else +/* refcount macros not defined without refcounting, caller must #ifdef now */ +#endif /* DUK_USE_REFERENCE_COUNTING */ + +/* + * Note: type is treated as a field separate from flags, so some masking is + * involved in the macros below. + */ + +#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags) + +#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK) +#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \ + (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \ + } while (0) + +#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK) +#define DUK_HEAPHDR_SET_TYPE(h,val) do { \ + (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \ + } while (0) + +#define DUK_HEAPHDR_HTYPE_VALID(h) ( \ + DUK_HEAPHDR_GET_TYPE((h)) >= DUK_HTYPE_MIN && \ + DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \ + ) + +#define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval) do { \ + (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \ + ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \ + } while (0) + +#define DUK_HEAPHDR_SET_FLAG_BITS(h,bits) do { \ + DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \ + (h)->h_flags |= (bits); \ + } while (0) + +#define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits) do { \ + DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \ + (h)->h_flags &= ~((bits)); \ + } while (0) + +#define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits) (((h)->h_flags & (bits)) != 0) + +#define DUK_HEAPHDR_SET_REACHABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE) +#define DUK_HEAPHDR_CLEAR_REACHABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE) +#define DUK_HEAPHDR_HAS_REACHABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE) + +#define DUK_HEAPHDR_SET_TEMPROOT(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT) +#define DUK_HEAPHDR_CLEAR_TEMPROOT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT) +#define DUK_HEAPHDR_HAS_TEMPROOT(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT) + +#define DUK_HEAPHDR_SET_FINALIZABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE) +#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE) +#define DUK_HEAPHDR_HAS_FINALIZABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE) + +#define DUK_HEAPHDR_SET_FINALIZED(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED) +#define DUK_HEAPHDR_CLEAR_FINALIZED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED) +#define DUK_HEAPHDR_HAS_FINALIZED(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED) + +#define DUK_HEAPHDR_SET_READONLY(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY) +#define DUK_HEAPHDR_CLEAR_READONLY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY) +#define DUK_HEAPHDR_HAS_READONLY(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY) + +/* get or set a range of flags; m=first bit number, n=number of bits */ +#define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n) (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL)) + +#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \ + (h)->h_flags = \ + ((h)->h_flags & (~(((1 << (n)) - 1) << (m)))) \ + | ((v) << (m)); \ + } while (0) + +/* init pointer fields to null */ +#if defined(DUK_USE_DOUBLE_LINKED_HEAP) +#define DUK_HEAPHDR_INIT_NULLS(h) do { \ + DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \ + DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \ + } while (0) +#else +#define DUK_HEAPHDR_INIT_NULLS(h) do { \ + DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \ + } while (0) +#endif + +#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */ + +/* + * Assert helpers + */ + +/* Check that prev/next links are consistent: if e.g. h->prev is != NULL, + * h->prev->next should point back to h. + */ +#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_ASSERTIONS) +#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do { \ + if ((h) != NULL) { \ + duk_heaphdr *h__prev, *h__next; \ + h__prev = DUK_HEAPHDR_GET_PREV((heap), (h)); \ + h__next = DUK_HEAPHDR_GET_NEXT((heap), (h)); \ + DUK_ASSERT(h__prev == NULL || (DUK_HEAPHDR_GET_NEXT((heap), h__prev) == (h))); \ + DUK_ASSERT(h__next == NULL || (DUK_HEAPHDR_GET_PREV((heap), h__next) == (h))); \ + } \ + } while (0) +#else +#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0) +#endif + +/* + * Reference counting helper macros. The macros take a thread argument + * and must thus always be executed in a specific thread context. The + * thread argument is needed for features like finalization. Currently + * it is not required for INCREF, but it is included just in case. + * + * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not + * defined without DUK_USE_REFERENCE_COUNTING, so caller must #ifdef + * around them. + */ + +#if defined(DUK_USE_REFERENCE_COUNTING) + +#if defined(DUK_USE_ROM_OBJECTS) +/* With ROM objects "needs refcount update" is true when the value is + * heap allocated and is not a ROM object. + */ +/* XXX: double evaluation for 'tv' argument. */ +#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \ + (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv)))) +#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h))) +#else /* DUK_USE_ROM_OBJECTS */ +/* Without ROM objects "needs refcount update" == is heap allocated. */ +#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv)) +#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1 +#endif /* DUK_USE_ROM_OBJECTS */ + +/* Fast variants, inline refcount operations except for refzero handling. + * Can be used explicitly when speed is always more important than size. + * For a good compiler and a single file build, these are basically the + * same as a forced inline. + */ +#define DUK_TVAL_INCREF_FAST(thr,tv) do { \ + duk_tval *duk__tv = (tv); \ + DUK_ASSERT(duk__tv != NULL); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ + duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + } \ + } while (0) +#define DUK_TVAL_DECREF_FAST(thr,tv) do { \ + duk_tval *duk__tv = (tv); \ + DUK_ASSERT(duk__tv != NULL); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ + duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ + if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ + duk_heaphdr_refzero((thr), duk__h); \ + } \ + } \ + } while (0) +#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \ + duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ + DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + } \ + } while (0) +#define DUK_HEAPHDR_DECREF_FAST(thr,h) do { \ + duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ + if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ + if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ + duk_heaphdr_refzero((thr), duk__h); \ + } \ + } \ + } while (0) + +/* Slow variants, call to a helper to reduce code size. + * Can be used explicitly when size is always more important than speed. + */ +#define DUK_TVAL_INCREF_SLOW(thr,tv) do { \ + duk_tval_incref((tv)); \ + } while (0) +#define DUK_TVAL_DECREF_SLOW(thr,tv) do { \ + duk_tval_decref((thr), (tv)); \ + } while (0) +#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { \ + duk_heaphdr_incref((duk_heaphdr *) (h)); \ + } while (0) +#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { \ + duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); \ + } while (0) + +/* Default variants. Selection depends on speed/size preference. + * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary + * is about +1kB for _FAST variants. + */ +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv)) +#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv)) +#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h)) +#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST((thr),(h)) +#else +#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv)) +#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv)) +#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h)) +#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h)) +#endif + +/* Casting convenience. */ +#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h)) +#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h)) +#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h)) +#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HNATIVEFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HNATIVEFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HBUFFEROBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HBUFFEROBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj) + +/* Convenience for some situations; the above macros don't allow NULLs + * for performance reasons. + */ +#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \ + } \ + } while (0) + +/* + * Macros to set a duk_tval and update refcount of the target (decref the + * old value and incref the new value if necessary). This is both performance + * and footprint critical; any changes made should be measured for size/speed. + */ + +#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_UNDEFINED(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_UNUSED(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NULL(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NAN(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#else +#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ + DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_STRING(tv__dst, (newval)); \ + DUK_HSTRING_INCREF((thr), (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ + DUK_HOBJECT_INCREF((thr), (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ + DUK_HBUFFER_INCREF((thr), (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups, + * etc, so it's very important for performance. Measure when changing. + * + * NOTE: the source and destination duk_tval pointers may be the same, and + * the macros MUST deal with that correctly. + */ + +/* Original idiom used, minimal code size. */ +#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ + duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \ + tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + DUK_TVAL_INCREF((thr), tv__src); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +/* Faster alternative: avoid making a temporary copy of tvptr_dst and use + * fast incref/decref macros. + */ +#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \ + duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ + tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ + DUK_TVAL_INCREF_FAST((thr), tv__src); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \ + h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ + DUK_ASSERT(h__obj != NULL); \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ + } else { \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + } \ + } while (0) + +/* XXX: no optimized variants yet */ +#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 +#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 +#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 +#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 +#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0 +#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0 +#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0 +#else +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */ +#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 +#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 +#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 +#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 +#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 + +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +/* Optimized for speed. */ +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1 +#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#else +/* Optimized for size. */ +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#endif + +#else /* DUK_USE_REFERENCE_COUNTING */ + +#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */ +#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HNATIVEFUNCTION_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HNATIVEFUNCTION_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFEROBJECT_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFEROBJECT_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ + +#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_UNDEFINED(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_UNUSED(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NULL(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NAN(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#else +#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ + DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_STRING(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ + duk_tval *tv__dst, *tv__src; \ + tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 +#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 +#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 +#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 +#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0 +#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0 +#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0 +#else +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */ +#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 +#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 +#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 +#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 +#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 + +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 + +#endif /* DUK_USE_REFERENCE_COUNTING */ + +#endif /* DUK_HEAPHDR_H_INCLUDED */ +/* + * Internal API calls which have (stack and other) semantics similar + * to the public API. + */ + +#ifndef DUK_API_INTERNAL_H_INCLUDED +#define DUK_API_INTERNAL_H_INCLUDED + +/* duk_push_sprintf constants */ +#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L +#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L) + +/* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not + * blamed as source of error for error fileName / lineNumber. + */ +#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24) + +/* Valstack resize flags */ +#define DUK_VSRESIZE_FLAG_SHRINK (1 << 0) +#define DUK_VSRESIZE_FLAG_COMPACT (1 << 1) +#define DUK_VSRESIZE_FLAG_THROW (1 << 2) + +/* Current convention is to use duk_size_t for value stack sizes and global indices, + * and duk_idx_t for local frame indices. + */ +DUK_INTERNAL_DECL +duk_bool_t duk_valstack_resize_raw(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags); + +#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index); +#endif + +DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv); + +/* Push the current 'this' binding; throw TypeError if binding is not object + * coercible (CheckObjectCoercible). + */ +DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_context *ctx); + +/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */ +DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx); + +/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */ +DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx); + +/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must + * make sure there's an active callstack entry. Note that the returned pointer + * is unstable with regards to side effects. + */ +DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx); + +/* XXX: add fastint support? */ +#define duk_push_u64(ctx,val) \ + duk_push_number((ctx), (duk_double_t) (val)) +#define duk_push_i64(ctx,val) \ + duk_push_number((ctx), (duk_double_t) (val)) + +/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */ +#define duk_push_u32(ctx,val) \ + duk_push_uint((ctx), (duk_uint_t) (val)) +#define duk_push_i32(ctx,val) \ + duk_push_int((ctx), (duk_int_t) (val)) + +/* sometimes stack and array indices need to go on the stack */ +#define duk_push_idx(ctx,val) \ + duk_push_int((ctx), (duk_int_t) (val)) +#define duk_push_uarridx(ctx,val) \ + duk_push_uint((ctx), (duk_uint_t) (val)) +#define duk_push_size_t(ctx,val) \ + duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */ + +DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index); + +DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum); + +#if 0 /* This would be pointless: unexpected type and lightfunc would both return NULL */ +DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index); +#endif +DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index); + +#if 0 /*unused*/ +DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index); +#endif + +DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index); +#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ +DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index); +#endif +DUK_INTERNAL_DECL void duk_to_object_class_string_top(duk_context *ctx); +#if !defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL_DECL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h); +#endif + +DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */ +DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval); +DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval); +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index); +#endif + +DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index); + +DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum); + +DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index); + +DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h); +DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx); +DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h); +DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h); +#define duk_push_hthread(ctx,h) \ + duk_push_hobject((ctx), (duk_hobject *) (h)) +#define duk_push_hcompiledfunction(ctx,h) \ + duk_push_hobject((ctx), (duk_hobject *) (h)) +#define duk_push_hnativefunction(ctx,h) \ + duk_push_hobject((ctx), (duk_hobject *) (h)) +DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx); +DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); +DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto); +DUK_INTERNAL_DECL duk_idx_t duk_push_object_internal(duk_context *ctx); +DUK_INTERNAL_DECL duk_idx_t duk_push_compiledfunction(duk_context *ctx); +DUK_INTERNAL_DECL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs); +DUK_INTERNAL_DECL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs); + +DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz); +DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv); +DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv); +DUK_INTERNAL_DECL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); + +#if !defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv); +#endif + +DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [val] */ +DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [val] -> [] */ +DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */ +DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */ + +DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */ + +DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags); /* [key val] -> [] */ +DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags); /* [val] -> [] */ +DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */ +DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */ +DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [] -> [] */ + +/* These are macros for now, but could be separate functions to reduce code + * footprint (check call site count before refactoring). + */ +#define duk_xdef_prop_wec(ctx,obj_index) \ + duk_xdef_prop((ctx), (obj_index), DUK_PROPDESC_FLAGS_WEC) +#define duk_xdef_prop_index_wec(ctx,obj_index,arr_index) \ + duk_xdef_prop_index((ctx), (obj_index), (arr_index), DUK_PROPDESC_FLAGS_WEC) +#define duk_xdef_prop_stridx_wec(ctx,obj_index,stridx) \ + duk_xdef_prop_stridx((ctx), (obj_index), (stridx), DUK_PROPDESC_FLAGS_WEC) + +/* Set object 'length'. */ +DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length); + +/* Raw internal valstack access macros: access is unsafe so call site + * must have a guarantee that the index is valid. When that is the case, + * using these macro results in faster and smaller code than duk_get_tval(). + * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts. + */ +#define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \ + (DUK_ASSERT_EXPR((idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx)))) +#define DUK_ASSERT_VALID_POSIDX(ctx,idx) \ + (DUK_ASSERT_EXPR((idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx)))) +#define DUK_GET_TVAL_NEGIDX(ctx,idx) \ + (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx)) +#define DUK_GET_TVAL_POSIDX(ctx,idx) \ + (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_bottom + (idx)) +#define DUK_GET_HOBJECT_NEGIDX(ctx,idx) \ + (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_top + (idx))) +#define DUK_GET_HOBJECT_POSIDX(ctx,idx) \ + (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx))) + +#endif /* DUK_API_INTERNAL_H_INCLUDED */ +/* + * Heap string representation. + * + * Strings are byte sequences ordinarily stored in extended UTF-8 format, + * allowing values larger than the official UTF-8 range (used internally) + * and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format). + * Strings may also be invalid UTF-8 altogether which is the case e.g. with + * strings used as internal property names and raw buffers converted to + * strings. In such cases the 'clen' field contains an inaccurate value. + * + * Ecmascript requires support for 32-bit long strings. However, since each + * 16-bit codepoint can take 3 bytes in CESU-8, this representation can only + * support about 1.4G codepoint long strings in extreme cases. This is not + * really a practical issue. + */ + +#ifndef DUK_HSTRING_H_INCLUDED +#define DUK_HSTRING_H_INCLUDED + +/* Impose a maximum string length for now. Restricted artificially to + * ensure adding a heap header length won't overflow size_t. The limit + * should be synchronized with DUK_HBUFFER_MAX_BYTELEN. + * + * E5.1 makes provisions to support strings longer than 4G characters. + * This limit should be eliminated on 64-bit platforms (and increased + * closer to maximum support on 32-bit platforms). + */ + +#if defined(DUK_USE_STRLEN16) +#define DUK_HSTRING_MAX_BYTELEN (0x0000ffffUL) +#else +#define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL) +#endif + +/* XXX: could add flags for "is valid CESU-8" (Ecmascript compatible strings), + * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not, + * regexp bytecode is), and "contains non-BMP characters". These are not + * needed right now. + */ + +#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */ +#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */ +#define DUK_HSTRING_FLAG_INTERNAL DUK_HEAPHDR_USER_FLAG(2) /* string is internal */ +#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(3) /* string is a reserved word (non-strict) */ +#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (strict) */ +#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(5) /* string is 'eval' or 'arguments' */ +#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(6) /* string data is external (duk_hstring_external) */ + +#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) +#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) +#define DUK_HSTRING_HAS_INTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL) +#define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) +#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) +#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) +#define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) + +#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) +#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) +#define DUK_HSTRING_SET_INTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL) +#define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) +#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) +#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) +#define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) + +#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) +#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) +#define DUK_HSTRING_CLEAR_INTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL) +#define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) +#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) +#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) +#define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) + +#if 0 /* Slightly smaller code without explicit flag, but explicit flag + * is very useful when 'clen' is dropped. + */ +#define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x))) +#endif +#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) +#define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0) + +#if defined(DUK_USE_STRHASH16) +#define DUK_HSTRING_GET_HASH(x) ((x)->hdr.h_flags >> 16) +#define DUK_HSTRING_SET_HASH(x,v) do { \ + (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | ((v) << 16); \ + } while (0) +#else +#define DUK_HSTRING_GET_HASH(x) ((x)->hash) +#define DUK_HSTRING_SET_HASH(x,v) do { \ + (x)->hash = (v); \ + } while (0) +#endif + +#if defined(DUK_USE_STRLEN16) +#define DUK_HSTRING_GET_BYTELEN(x) ((x)->hdr.h_strextra16) +#define DUK_HSTRING_SET_BYTELEN(x,v) do { \ + (x)->hdr.h_strextra16 = (v); \ + } while (0) +#if defined(DUK_USE_HSTRING_CLEN) +#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16) +#define DUK_HSTRING_SET_CHARLEN(x,v) do { \ + (x)->clen16 = (v); \ + } while (0) +#else +#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) +#define DUK_HSTRING_SET_CHARLEN(x,v) do { \ + DUK_ASSERT(0); /* should never be called */ \ + } while (0) +#endif +#else +#define DUK_HSTRING_GET_BYTELEN(x) ((x)->blen) +#define DUK_HSTRING_SET_BYTELEN(x,v) do { \ + (x)->blen = (v); \ + } while (0) +#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen) +#define DUK_HSTRING_SET_CHARLEN(x,v) do { \ + (x)->clen = (v); \ + } while (0) +#endif + +#if defined(DUK_USE_HSTRING_EXTDATA) +#define DUK_HSTRING_GET_EXTDATA(x) \ + ((x)->extdata) +#define DUK_HSTRING_GET_DATA(x) \ + (DUK_HSTRING_HAS_EXTDATA((x)) ? \ + DUK_HSTRING_GET_EXTDATA((const duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1))) +#else +#define DUK_HSTRING_GET_DATA(x) \ + ((const duk_uint8_t *) ((x) + 1)) +#endif + +#define DUK_HSTRING_GET_DATA_END(x) \ + (DUK_HSTRING_GET_DATA((x)) + (x)->blen) + +/* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */ +#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL) + +/* get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX); + * avoids helper call if string has no array index value. + */ +#define DUK_HSTRING_GET_ARRIDX_FAST(h) \ + (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX) + +/* slower but more compact variant */ +#define DUK_HSTRING_GET_ARRIDX_SLOW(h) \ + (duk_js_to_arrayindex_string_helper((h))) + +/* + * Misc + */ + +struct duk_hstring { + /* Smaller heaphdr than for other objects, because strings are held + * in string intern table which requires no link pointers. Much of + * the 32-bit flags field is unused by flags, so we can stuff a 16-bit + * field in there. + */ + duk_heaphdr_string hdr; + + /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the + * shared heap header. Good hashing needs more hash bits though. + */ + + /* string hash */ +#if defined(DUK_USE_STRHASH16) + /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */ +#else + duk_uint32_t hash; +#endif + + /* length in bytes (not counting NUL term) */ +#if defined(DUK_USE_STRLEN16) + /* placed in duk_heaphdr_string */ +#else + duk_uint32_t blen; +#endif + + /* length in codepoints (must be E5 compatible) */ +#if defined(DUK_USE_STRLEN16) +#if defined(DUK_USE_HSTRING_CLEN) + duk_uint16_t clen16; +#else + /* computed live */ +#endif +#else + duk_uint32_t clen; +#endif + + /* + * String value of 'blen+1' bytes follows (+1 for NUL termination + * convenience for C API). No alignment needs to be guaranteed + * for strings, but fields above should guarantee alignment-by-4 + * (but not alignment-by-8). + */ +}; + +/* The external string struct is defined even when the feature is inactive. */ +struct duk_hstring_external { + duk_hstring str; + + /* + * For an external string, the NUL-terminated string data is stored + * externally. The user must guarantee that data behind this pointer + * doesn't change while it's used. + */ + + const duk_uint8_t *extdata; +}; + +/* + * Prototypes + */ + +DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos); + +#if !defined(DUK_USE_HSTRING_CLEN) +DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); +#endif + +#endif /* DUK_HSTRING_H_INCLUDED */ +/* + * Heap object representation. + * + * Heap objects are used for Ecmascript objects, arrays, and functions, + * but also for internal control like declarative and object environment + * records. Compiled functions, native functions, and threads are also + * objects but with an extended C struct. + * + * Objects provide the required Ecmascript semantics and exotic behaviors + * especially for property access. + * + * Properties are stored in three conceptual parts: + * + * 1. A linear 'entry part' contains ordered key-value-attributes triples + * and is the main method of string properties. + * + * 2. An optional linear 'array part' is used for array objects to store a + * (dense) range of [0,N[ array indexed entries with default attributes + * (writable, enumerable, configurable). If the array part would become + * sparse or non-default attributes are required, the array part is + * abandoned and moved to the 'entry part'. + * + * 3. An optional 'hash part' is used to optimize lookups of the entry + * part; it is used only for objects with sufficiently many properties + * and can be abandoned without loss of information. + * + * These three conceptual parts are stored in a single memory allocated area. + * This minimizes memory allocation overhead but also means that all three + * parts are resized together, and makes property access a bit complicated. + */ + +#ifndef DUK_HOBJECT_H_INCLUDED +#define DUK_HOBJECT_H_INCLUDED + +/* Object flag. There are currently 26 flag bits available. Make sure + * this stays in sync with debugger object inspection code. + */ +#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */ +#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */ +#define DUK_HOBJECT_FLAG_BOUND DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */ +#define DUK_HOBJECT_FLAG_COMPILEDFUNCTION DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompiledfunction) */ +#define DUK_HOBJECT_FLAG_NATIVEFUNCTION DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnativefunction) */ +#define DUK_HOBJECT_FLAG_BUFFEROBJECT DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufferobject) (always exotic) */ +#define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */ +#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */ +#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */ +#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */ +#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompiledfunction) */ +#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */ +#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */ +#define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */ +#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */ +#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */ +#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */ +#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(18) /* Duktape/C (nativefunction) object, exotic 'length' */ +#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */ + +#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20) +#define DUK_HOBJECT_FLAG_CLASS_BITS 5 + +#define DUK_HOBJECT_GET_CLASS_NUMBER(h) \ + DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS) +#define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \ + DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v)) + +#define DUK_HOBJECT_GET_CLASS_MASK(h) \ + (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)) + +/* Macro for creating flag initializer from a class number. + * Unsigned type cast is needed to avoid warnings about coercing + * a signed integer to an unsigned one; the largest class values + * have the highest bit (bit 31) set which causes this. + */ +#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE) + +/* E5 Section 8.6.2 + custom classes */ +#define DUK_HOBJECT_CLASS_UNUSED 0 +#define DUK_HOBJECT_CLASS_ARGUMENTS 1 +#define DUK_HOBJECT_CLASS_ARRAY 2 +#define DUK_HOBJECT_CLASS_BOOLEAN 3 +#define DUK_HOBJECT_CLASS_DATE 4 +#define DUK_HOBJECT_CLASS_ERROR 5 +#define DUK_HOBJECT_CLASS_FUNCTION 6 +#define DUK_HOBJECT_CLASS_JSON 7 +#define DUK_HOBJECT_CLASS_MATH 8 +#define DUK_HOBJECT_CLASS_NUMBER 9 +#define DUK_HOBJECT_CLASS_OBJECT 10 +#define DUK_HOBJECT_CLASS_REGEXP 11 +#define DUK_HOBJECT_CLASS_STRING 12 +#define DUK_HOBJECT_CLASS_GLOBAL 13 +#define DUK_HOBJECT_CLASS_OBJENV 14 /* custom */ +#define DUK_HOBJECT_CLASS_DECENV 15 /* custom */ +#define DUK_HOBJECT_CLASS_BUFFER 16 /* custom; implies DUK_HOBJECT_IS_BUFFEROBJECT */ +#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */ +#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */ +#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFFEROBJECT */ +#define DUK_HOBJECT_CLASS_DATAVIEW 20 +#define DUK_HOBJECT_CLASS_INT8ARRAY 21 +#define DUK_HOBJECT_CLASS_UINT8ARRAY 22 +#define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23 +#define DUK_HOBJECT_CLASS_INT16ARRAY 24 +#define DUK_HOBJECT_CLASS_UINT16ARRAY 25 +#define DUK_HOBJECT_CLASS_INT32ARRAY 26 +#define DUK_HOBJECT_CLASS_UINT32ARRAY 27 +#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28 +#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29 +#define DUK_HOBJECT_CLASS_MAX 29 + +/* class masks */ +#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL) +#define DUK_HOBJECT_CMASK_UNUSED (1UL << DUK_HOBJECT_CLASS_UNUSED) +#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS) +#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY) +#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN) +#define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE) +#define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR) +#define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION) +#define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON) +#define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH) +#define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER) +#define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT) +#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP) +#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING) +#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL) +#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV) +#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV) +#define DUK_HOBJECT_CMASK_BUFFER (1UL << DUK_HOBJECT_CLASS_BUFFER) +#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER) +#define DUK_HOBJECT_CMASK_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD) +#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER) +#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW) +#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY) +#define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY) +#define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY) +#define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY) +#define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY) +#define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY) +#define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY) +#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY) +#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY) + +#define DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS \ + (DUK_HOBJECT_CMASK_BUFFER | \ + DUK_HOBJECT_CMASK_ARRAYBUFFER | \ + DUK_HOBJECT_CMASK_DATAVIEW | \ + DUK_HOBJECT_CMASK_INT8ARRAY | \ + DUK_HOBJECT_CMASK_UINT8ARRAY | \ + DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \ + DUK_HOBJECT_CMASK_INT16ARRAY | \ + DUK_HOBJECT_CMASK_UINT16ARRAY | \ + DUK_HOBJECT_CMASK_INT32ARRAY | \ + DUK_HOBJECT_CMASK_UINT32ARRAY | \ + DUK_HOBJECT_CMASK_FLOAT32ARRAY | \ + DUK_HOBJECT_CMASK_FLOAT64ARRAY) + +#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV) +#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV) +#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h))) +#define DUK_HOBJECT_IS_ARRAY(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY) +#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) +#define DUK_HOBJECT_IS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) +#define DUK_HOBJECT_IS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) +#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) + +#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ + DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \ + DUK_HOBJECT_FLAG_NATIVEFUNCTION) + +#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ + DUK_HOBJECT_FLAG_BOUND | \ + DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \ + DUK_HOBJECT_FLAG_NATIVEFUNCTION) + +#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ + DUK_HOBJECT_FLAG_BOUND | \ + DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \ + DUK_HOBJECT_FLAG_NATIVEFUNCTION) + +/* object has any exotic behavior(s) */ +#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ + DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \ + DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \ + DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \ + DUK_HOBJECT_FLAG_BUFFEROBJECT | \ + DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) + +#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS) + +#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) +#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) +#define DUK_HOBJECT_HAS_BOUND(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND) +#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) +#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) +#define DUK_HOBJECT_HAS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) +#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) +#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) +#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) +#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) +#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) +#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) +#define DUK_HOBJECT_HAS_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) +#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) +#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) +#define DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) +#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) + +#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) +#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) +#define DUK_HOBJECT_SET_BOUND(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND) +#define DUK_HOBJECT_SET_COMPILEDFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) +#define DUK_HOBJECT_SET_NATIVEFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) +#define DUK_HOBJECT_SET_BUFFEROBJECT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) +#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) +#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) +#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) +#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) +#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) +#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) +#define DUK_HOBJECT_SET_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) +#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) +#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) +#define DUK_HOBJECT_SET_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) +#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) + +#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) +#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) +#define DUK_HOBJECT_CLEAR_BOUND(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND) +#define DUK_HOBJECT_CLEAR_COMPILEDFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) +#define DUK_HOBJECT_CLEAR_NATIVEFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) +#define DUK_HOBJECT_CLEAR_BUFFEROBJECT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) +#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) +#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) +#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) +#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) +#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) +#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) +#define DUK_HOBJECT_CLEAR_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) +#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) +#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) +#define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) +#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) + +/* flags used for property attributes in duk_propdesc and packed flags */ +#define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */ +#define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */ +#define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */ +#define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */ +#define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored + * (used by e.g. buffer virtual properties) + */ +#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \ + DUK_PROPDESC_FLAG_ENUMERABLE | \ + DUK_PROPDESC_FLAG_CONFIGURABLE | \ + DUK_PROPDESC_FLAG_ACCESSOR) + +/* additional flags which are passed in the same flags argument as property + * flags but are not stored in object properties. + */ +#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */ + +/* convenience */ +#define DUK_PROPDESC_FLAGS_NONE 0 +#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE) +#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE) +#define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE) +#define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE) +#define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE) +#define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE) +#define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \ + DUK_PROPDESC_FLAG_ENUMERABLE | \ + DUK_PROPDESC_FLAG_CONFIGURABLE) + +/* flags for duk_hobject_get_own_propdesc() and variants */ +#define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */ +#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */ + +/* + * Macro for object validity check + * + * Assert for currently guaranteed relations between flags, for instance. + */ + +#define DUK_ASSERT_HOBJECT_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \ + DUK_ASSERT(!DUK_HOBJECT_IS_BUFFEROBJECT((h)) || \ + (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_BUFFER || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT16ARRAY || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT16ARRAY || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT32ARRAY || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \ + DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \ + } while (0) + +/* + * Macros to access the 'props' allocation. + */ + +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HOBJECT_GET_PROPS(heap,h) \ + ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16)) +#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \ + ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \ + } while (0) +#else +#define DUK_HOBJECT_GET_PROPS(heap,h) \ + ((h)->props) +#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \ + (h)->props = (duk_uint8_t *) (x); \ + } while (0) +#endif + +#if defined(DUK_USE_HOBJECT_LAYOUT_1) +/* LAYOUT 1 */ +#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ + ((duk_hstring **) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) \ + )) +#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ + ((duk_propvalue *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \ + )) +#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ + ((duk_uint8_t *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \ + )) +#define DUK_HOBJECT_A_GET_BASE(heap,h) \ + ((duk_tval *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \ + )) +#define DUK_HOBJECT_H_GET_BASE(heap,h) \ + ((duk_uint32_t *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ + DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ + )) +#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ + ( \ + (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ + (n_arr) * sizeof(duk_tval) + \ + (n_hash) * sizeof(duk_uint32_t) \ + ) +#define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \ + (set_e_k) = (duk_hstring **) (void *) (p_base); \ + (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \ + (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \ + (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \ + (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \ + } while (0) +#elif defined(DUK_USE_HOBJECT_LAYOUT_2) +/* LAYOUT 2 */ +#if (DUK_USE_ALIGN_BY == 4) +#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03) +#elif (DUK_USE_ALIGN_BY == 8) +#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07) +#elif (DUK_USE_ALIGN_BY == 1) +#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0 +#else +#error invalid DUK_USE_ALIGN_BY +#endif +#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ + ((duk_hstring **) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \ + )) +#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ + ((duk_propvalue *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) \ + )) +#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ + ((duk_uint8_t *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \ + )) +#define DUK_HOBJECT_A_GET_BASE(heap,h) \ + ((duk_tval *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ + DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \ + )) +#define DUK_HOBJECT_H_GET_BASE(heap,h) \ + ((duk_uint32_t *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ + DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \ + DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ + )) +#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ + ( \ + (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ + DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \ + (n_arr) * sizeof(duk_tval) + \ + (n_hash) * sizeof(duk_uint32_t) \ + ) +#define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \ + (set_e_pv) = (duk_propvalue *) (void *) (p_base); \ + (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \ + (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \ + (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \ + sizeof(duk_uint8_t) * (n_ent) + \ + DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \ + (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \ + } while (0) +#elif defined(DUK_USE_HOBJECT_LAYOUT_3) +/* LAYOUT 3 */ +#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ + ((duk_hstring **) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \ + DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ + )) +#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ + ((duk_propvalue *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) \ + )) +#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ + ((duk_uint8_t *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \ + DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \ + DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \ + )) +#define DUK_HOBJECT_A_GET_BASE(heap,h) \ + ((duk_tval *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \ + )) +#define DUK_HOBJECT_H_GET_BASE(heap,h) \ + ((duk_uint32_t *) (void *) ( \ + DUK_HOBJECT_GET_PROPS((heap), (h)) + \ + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \ + DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ + )) +#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ + ( \ + (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \ + (n_arr) * sizeof(duk_tval) + \ + (n_hash) * sizeof(duk_uint32_t) \ + ) +#define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \ + (set_e_pv) = (duk_propvalue *) (void *) (p_base); \ + (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \ + (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \ + (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \ + (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \ + } while (0) +#else +#error invalid hobject layout defines +#endif /* hobject property layout */ + +#define DUK_HOBJECT_P_ALLOC_SIZE(h) \ + DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h))) + +#define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)]) +#define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)]) +#define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)]) +#define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)]) +#define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v) +#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v) +#define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get) +#define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get) +#define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set) +#define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set) +#define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)]) +#define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)]) +#define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)]) +#define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)]) +#define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)]) +#define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)]) + +#define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \ + DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \ + } while (0) +#define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \ + DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \ + } while (0) +#define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \ + DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \ + } while (0) +#define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \ + DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \ + } while (0) +#define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \ + DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \ + } while (0) +#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \ + DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \ + } while (0) +#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \ + DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \ + } while (0) +#define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \ + DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */ +#define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \ + DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \ + } while (0) + +#define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \ + DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \ + } while (0) + +#define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \ + DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \ + } while (0) + +#define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0) +#define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0) +#define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0) +#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0) + +#define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE) +#define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE) +#define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE) +#define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR) + +#define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE) +#define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE) +#define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE) +#define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR) + +#define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0) +#define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0) +#define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0) +#define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0) + +#define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL +#define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL + +/* + * Macros for accessing size fields + */ + +#if defined(DUK_USE_OBJSIZES16) +#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16) +#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0) +#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16) +#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0) +#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++) +#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16) +#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0) +#if defined(DUK_USE_HOBJECT_HASH_PART) +#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16) +#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0) +#else +#define DUK_HOBJECT_GET_HSIZE(h) 0 +#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0) +#endif +#else +#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size) +#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0) +#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next) +#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0) +#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++) +#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size) +#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0) +#if defined(DUK_USE_HOBJECT_HASH_PART) +#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size) +#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0) +#else +#define DUK_HOBJECT_GET_HSIZE(h) 0 +#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0) +#endif +#endif + +/* + * Misc + */ + +/* Maximum prototype traversal depth. Sanity limit which handles e.g. + * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4). + */ +#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L + +/* Maximum traversal depth for "bound function" chains. */ +#define DUK_HOBJECT_BOUND_CHAIN_SANITY 10000L + +/* + * Ecmascript [[Class]] + */ + +/* range check not necessary because all 4-bit values are mapped */ +#define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)] + +#define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \ + DUK_HEAP_GET_STRING( \ + (heap), \ + DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \ + ) + +/* + * Macros for property handling + */ + +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \ + ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16)) +#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \ + (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \ + } while (0) +#else +#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \ + ((h)->prototype) +#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \ + (h)->prototype = (x); \ + } while (0) +#endif + +/* note: this updates refcounts */ +#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p)) + +/* + * Resizing and hash behavior + */ + +/* Sanity limit on max number of properties (allocated, not necessarily used). + * This is somewhat arbitrary, but if we're close to 2**32 properties some + * algorithms will fail (e.g. hash size selection, next prime selection). + * Also, we use negative array/entry table indices to indicate 'not found', + * so anything above 0x80000000 will cause trouble now. + */ +#if defined(DUK_USE_OBJSIZES16) +#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL +#else +#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */ +#endif + +/* higher value conserves memory; also note that linear scan is cache friendly */ +#define DUK_HOBJECT_E_USE_HASH_LIMIT 32 + +/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */ +#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */ + +/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */ +#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */ + +/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */ +/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */ +#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */ + +/* internal align target for props allocation, must be 2*n for some n */ +#if (DUK_USE_ALIGN_BY == 4) +#define DUK_HOBJECT_ALIGN_TARGET 4 +#elif (DUK_USE_ALIGN_BY == 8) +#define DUK_HOBJECT_ALIGN_TARGET 8 +#elif (DUK_USE_ALIGN_BY == 1) +#define DUK_HOBJECT_ALIGN_TARGET 1 +#else +#error invalid DUK_USE_ALIGN_BY +#endif + +/* controls for minimum entry part growth */ +#define DUK_HOBJECT_E_MIN_GROW_ADD 16 +#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ + +/* controls for minimum array part growth */ +#define DUK_HOBJECT_A_MIN_GROW_ADD 16 +#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ + +/* probe sequence */ +#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) +#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) + +/* + * PC-to-line constants + */ + +#define DUK_PC2LINE_SKIP 64 + +/* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */ +#define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8) + +/* + * Struct defs + */ + +struct duk_propaccessor { + duk_hobject *get; + duk_hobject *set; +}; + +union duk_propvalue { + /* The get/set pointers could be 16-bit pointer compressed but it + * would make no difference on 32-bit platforms because duk_tval is + * 8 bytes or more anyway. + */ + duk_tval v; + duk_propaccessor a; +}; + +struct duk_propdesc { + /* read-only values 'lifted' for ease of use */ + duk_small_int_t flags; + duk_hobject *get; + duk_hobject *set; + + /* for updating (all are set to < 0 for virtual properties) */ + duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */ + duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */ + duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */ +}; + +struct duk_hobject { + duk_heaphdr hdr; + + /* + * 'props' contains {key,value,flags} entries, optional array entries, and + * an optional hash lookup table for non-array entries in a single 'sliced' + * allocation. There are several layout options, which differ slightly in + * generated code size/speed and alignment/padding; duk_features.h selects + * the layout used. + * + * Layout 1 (DUK_USE_HOBJECT_LAYOUT_1): + * + * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) + * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) + * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable) + * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) + * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), + * 0xffffffffUL = unused, 0xfffffffeUL = deleted + * + * Layout 2 (DUK_USE_HOBJECT_LAYOUT_2): + * + * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) + * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) + * e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable) + * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) + * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), + * 0xffffffffUL = unused, 0xfffffffeUL = deleted + * + * Layout 3 (DUK_USE_HOBJECT_LAYOUT_3): + * + * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) + * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) + * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) + * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), + * 0xffffffffUL = unused, 0xfffffffeUL = deleted + * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable) + * + * In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms + * requiring 4 or 8 byte alignment. This ensures proper alignment + * for the entries, at the cost of memory footprint. However, it's + * probably preferable to use another layout on such platforms instead. + * + * In layout 2, the key and value parts are swapped to avoid padding + * the key array on platforms requiring alignment by 8. The flags part + * is padded to get alignment for array entries. The 'e_next' count does + * not need to be rounded as in layout 1. + * + * In layout 3, entry values and array values are always aligned properly, + * and assuming pointers are at most 8 bytes, so are the entry keys. Hash + * indices will be properly aligned (assuming pointers are at least 4 bytes). + * Finally, flags don't need additional alignment. This layout provides + * compact allocations without padding (even on platforms with alignment + * requirements) at the cost of a bit slower lookups. + * + * Objects with few keys don't have a hash index; keys are looked up linearly, + * which is cache efficient because the keys are consecutive. Larger objects + * have a hash index part which contains integer indexes to the entries part. + * + * A single allocation reduces memory allocation overhead but requires more + * work when any part needs to be resized. A sliced allocation for entries + * makes linear key matching faster on most platforms (more locality) and + * skimps on flags size (which would be followed by 3 bytes of padding in + * most architectures if entries were placed in a struct). + * + * 'props' also contains internal properties distinguished with a non-BMP + * prefix. Often used properties should be placed early in 'props' whenever + * possible to make accessing them as fast a possible. + */ + +#if defined(DUK_USE_HEAPPTR16) + /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like + * duk_hcompiledfunction) are not free to use h_extra16 for this reason. + */ +#else + duk_uint8_t *props; +#endif + + /* prototype: the only internal property lifted outside 'e' as it is so central */ +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t prototype16; +#else + duk_hobject *prototype; +#endif + +#if defined(DUK_USE_OBJSIZES16) + duk_uint16_t e_size16; + duk_uint16_t e_next16; + duk_uint16_t a_size16; +#if defined(DUK_USE_HOBJECT_HASH_PART) + duk_uint16_t h_size16; +#endif +#else + duk_uint32_t e_size; /* entry part size */ + duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */ + duk_uint32_t a_size; /* array part size (entirely gc reachable) */ +#if defined(DUK_USE_HOBJECT_HASH_PART) + duk_uint32_t h_size; /* hash part size or 0 if unused */ +#endif +#endif +}; + +/* + * Exposed data + */ + +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32]; +#endif /* !DUK_SINGLE_FILE */ + +/* + * Prototypes + */ + +/* alloc and init */ +DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags); +#if 0 /* unused */ +DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags); +#endif +DUK_INTERNAL_DECL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags); +DUK_INTERNAL_DECL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags); +DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags); +DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags); + +/* low-level property functions */ +DUK_INTERNAL_DECL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx); +DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key); +DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs); +DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags); + +/* XXX: when optimizing for guaranteed property slots, use a guaranteed + * slot for internal value; this call can then access it directly. + */ +#define duk_hobject_get_internal_value_tval_ptr(heap,obj) \ + duk_hobject_find_existing_entry_tval_ptr((heap), (obj), DUK_HEAP_STRING_INT_VALUE((heap))) + +/* core property functions */ +DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); + +/* internal property functions */ +#define DUK_DELPROP_FLAG_THROW (1 << 0) +#define DUK_DELPROP_FLAG_FORCE (1 << 1) +DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key); +DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); +DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags); +DUK_INTERNAL_DECL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags); +DUK_INTERNAL_DECL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length); /* XXX: duk_uarridx_t? */ +DUK_INTERNAL_DECL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj); +DUK_INTERNAL_DECL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* XXX: duk_uarridx_t? */ + +/* helpers for defineProperty() and defineProperties() */ +DUK_INTERNAL_DECL +void duk_hobject_prepare_property_descriptor(duk_context *ctx, + duk_idx_t idx_in, + duk_uint_t *out_defprop_flags, + duk_idx_t *out_idx_value, + duk_hobject **out_getter, + duk_hobject **out_setter); +DUK_INTERNAL_DECL +void duk_hobject_define_property_helper(duk_context *ctx, + duk_uint_t defprop_flags, + duk_hobject *obj, + duk_hstring *key, + duk_idx_t idx_value, + duk_hobject *get, + duk_hobject *set); + +/* Object built-in methods */ +DUK_INTERNAL_DECL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx); +DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags); + +/* internal properties */ +DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv); +DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj); + +/* hobject management functions */ +DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj); + +/* ES6 proxy */ +#if defined(DUK_USE_ES6_PROXY) +DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler); +DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj); +#endif + +/* enumeration */ +DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags); +DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value); + +/* macros */ +DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p); + +/* finalization */ +DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj); + +/* pc2line */ +#if defined(DUK_USE_PC2LINE) +DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length); +DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc); +#endif + +/* misc */ +DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop); + +#endif /* DUK_HOBJECT_H_INCLUDED */ +/* + * Heap compiled function (Ecmascript function) representation. + * + * There is a single data buffer containing the Ecmascript function's + * bytecode, constants, and inner functions. + */ + +#ifndef DUK_HCOMPILEDFUNCTION_H_INCLUDED +#define DUK_HCOMPILEDFUNCTION_H_INCLUDED + +/* + * Field accessor macros + */ + +/* XXX: casts could be improved, especially for GET/SET DATA */ + +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \ + ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16)) +#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \ + (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ + } while (0) +#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \ + ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16))) +#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \ + (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ + } while (0) +#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \ + ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16))) +#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \ + (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ + } while (0) +#else +#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \ + ((duk_hbuffer_fixed *) (void *) (h)->data) +#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \ + (h)->data = (duk_hbuffer *) (v); \ + } while (0) +#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \ + ((h)->funcs) +#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \ + (h)->funcs = (v); \ + } while (0) +#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \ + ((h)->bytecode) +#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \ + (h)->bytecode = (v); \ + } while (0) +#endif + +/* + * Accessor macros for function specific data areas + */ + +/* Note: assumes 'data' is always a fixed buffer */ +#define DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE(heap,h) \ + DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) + +#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap,h) \ + ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE((heap), (h))) + +#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap,h) \ + DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h)) + +#define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap,h) \ + DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h)) + +#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap,h) \ + ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h))) + +#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap,h) \ + ((duk_hobject **) (void *) DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h))) + +/* XXX: double evaluation of DUK_HCOMPILEDFUNCTION_GET_DATA() */ +#define DUK_HCOMPILEDFUNCTION_GET_CODE_END(heap,h) \ + ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) + \ + DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA((heap), h)))) + +#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(heap,h) \ + ( \ + (duk_size_t) \ + ( \ + ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END((heap), (h))) - \ + ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE((heap), (h))) \ + ) \ + ) + +#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(heap,h) \ + ( \ + (duk_size_t) \ + ( \ + ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END((heap), (h))) - \ + ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((heap), (h))) \ + ) \ + ) + +#define DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap,h) \ + ( \ + (duk_size_t) \ + ( \ + ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END((heap),(h))) - \ + ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((heap),(h))) \ + ) \ + ) + +#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap,h) \ + ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval))) + +#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap,h) \ + ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *))) + +#define DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(heap,h) \ + ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t))) + + +/* + * Main struct + */ + +struct duk_hcompiledfunction { + /* shared object part */ + duk_hobject obj; + + /* + * Pointers to function data area for faster access. Function + * data is a buffer shared between all closures of the same + * "template" function. The data buffer is always fixed (non- + * dynamic, hence stable), with a layout as follows: + * + * constants (duk_tval) + * inner functions (duk_hobject *) + * bytecode (duk_instr_t) + * + * Note: bytecode end address can be computed from 'data' buffer + * size. It is not strictly necessary functionally, assuming + * bytecode never jumps outside its allocated area. However, + * it's a safety/robustness feature for avoiding the chance of + * executing random data as bytecode due to a compiler error. + * + * Note: values in the data buffer must be incref'd (they will + * be decref'd on release) for every compiledfunction referring + * to the 'data' element. + */ + + /* Data area, fixed allocation, stable data ptrs. */ +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t data16; +#else + duk_hbuffer *data; +#endif + + /* No need for constants pointer (= same as data). + * + * When using 16-bit packing alignment to 4 is nice. 'funcs' will be + * 4-byte aligned because 'constants' are duk_tvals. For now the + * inner function pointers are not compressed, so that 'bytecode' will + * also be 4-byte aligned. + */ +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t funcs16; + duk_uint16_t bytecode16; +#else + duk_hobject **funcs; + duk_instr_t *bytecode; +#endif + + /* + * 'nregs' registers are allocated on function entry, at most 'nargs' + * are initialized to arguments, and the rest to undefined. Arguments + * above 'nregs' are not mapped to registers. All registers in the + * active stack range must be initialized because they are GC reachable. + * 'nargs' is needed so that if the function is given more than 'nargs' + * arguments, the additional arguments do not 'clobber' registers + * beyond 'nregs' which must be consistently initialized to undefined. + * + * Usually there is no need to know which registers are mapped to + * local variables. Registers may be allocated to variable in any + * way (even including gaps). However, a register-variable mapping + * must be the same for the duration of the function execution and + * the register cannot be used for anything else. + * + * When looking up variables by name, the '_Varmap' map is used. + * When an activation closes, registers mapped to arguments are + * copied into the environment record based on the same map. The + * reverse map (from register to variable) is not currently needed + * at run time, except for debugging, so it is not maintained. + */ + + duk_uint16_t nregs; /* regs to allocate */ + duk_uint16_t nargs; /* number of arguments allocated to regs */ + + /* + * Additional control information is placed into the object itself + * as internal properties to avoid unnecessary fields for the + * majority of functions. The compiler tries to omit internal + * control fields when possible. + * + * Function templates: + * + * { + * name: "func", // declaration, named function expressions + * fileName: + * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 }, + * _Formals: [ "arg1", "arg2" ], + * _Source: "function func(arg1, arg2) { ... }", + * _Pc2line: , + * } + * + * Function instances: + * + * { + * length: 2, + * prototype: { constructor: }, + * caller: , + * arguments: , + * name: "func", // declaration, named function expressions + * fileName: + * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 }, + * _Formals: [ "arg1", "arg2" ], + * _Source: "function func(arg1, arg2) { ... }", + * _Pc2line: , + * _Varenv: , + * _Lexenv: + * } + * + * More detailed description of these properties can be found + * in the documentation. + */ + +#if defined(DUK_USE_DEBUGGER_SUPPORT) + /* Line number range for function. Needed during debugging to + * determine active breakpoints. + */ + duk_uint32_t start_line; + duk_uint32_t end_line; +#endif +}; + +#endif /* DUK_HCOMPILEDFUNCTION_H_INCLUDED */ +/* + * Heap native function representation. + */ + +#ifndef DUK_HNATIVEFUNCTION_H_INCLUDED +#define DUK_HNATIVEFUNCTION_H_INCLUDED + +#define DUK_HNATIVEFUNCTION_NARGS_VARARGS ((duk_int16_t) -1) +#define DUK_HNATIVEFUNCTION_NARGS_MAX ((duk_int16_t) 0x7fff) + +struct duk_hnativefunction { + /* shared object part */ + duk_hobject obj; + + duk_c_function func; + duk_int16_t nargs; + duk_int16_t magic; + + /* The 'magic' field allows an opaque 16-bit field to be accessed by the + * Duktape/C function. This allows, for instance, the same native function + * to be used for a set of very similar functions, with the 'magic' field + * providing the necessary non-argument flags / values to guide the behavior + * of the native function. The value is signed on purpose: it is easier to + * convert a signed value to unsigned (simply AND with 0xffff) than vice + * versa. + * + * Note: cannot place nargs/magic into the heaphdr flags, because + * duk_hobject takes almost all flags already (and needs the spare). + */ +}; + +#endif /* DUK_HNATIVEFUNCTION_H_INCLUDED */ +/* + * Heap Buffer object representation. Used for all Buffer variants. + */ + +#ifndef DUK_HBUFFEROBJECT_H_INCLUDED +#define DUK_HBUFFEROBJECT_H_INCLUDED + +/* All element accessors are host endian now (driven by TypedArray spec). */ +#define DUK_HBUFFEROBJECT_ELEM_UINT8 0 +#define DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED 1 +#define DUK_HBUFFEROBJECT_ELEM_INT8 2 +#define DUK_HBUFFEROBJECT_ELEM_UINT16 3 +#define DUK_HBUFFEROBJECT_ELEM_INT16 4 +#define DUK_HBUFFEROBJECT_ELEM_UINT32 5 +#define DUK_HBUFFEROBJECT_ELEM_INT32 6 +#define DUK_HBUFFEROBJECT_ELEM_FLOAT32 7 +#define DUK_HBUFFEROBJECT_ELEM_FLOAT64 8 +#define DUK_HBUFFEROBJECT_ELEM_MAX 8 + +#define DUK_ASSERT_HBUFFEROBJECT_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT((h)->shift <= 3); \ + DUK_ASSERT((h)->elem_type <= DUK_HBUFFEROBJECT_ELEM_MAX); \ + DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8) || \ + ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) || \ + ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT8) || \ + ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT16) || \ + ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT16) || \ + ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT32) || \ + ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT32) || \ + ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT32) || \ + ((h)->shift == 3 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT64)); \ + DUK_ASSERT((h)->is_view == 0 || (h)->is_view == 1); \ + DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) (h))); \ + if ((h)->buf == NULL) { \ + DUK_ASSERT((h)->offset == 0); \ + DUK_ASSERT((h)->length == 0); \ + } else { \ + /* No assertions for offset or length; in particular, \ + * it's OK for length to be longer than underlying \ + * buffer. Just ensure they don't wrap when added. \ + */ \ + DUK_ASSERT((h)->offset + (h)->length >= (h)->offset); \ + } \ + } while (0) + +/* Get the current data pointer (caller must ensure buf != NULL) as a + * duk_uint8_t ptr. + */ +#define DUK_HBUFFEROBJECT_GET_SLICE_BASE(heap,h) \ + (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ + (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset)) + +/* True if slice is full, i.e. offset is zero and length covers the entire + * buffer. This status may change independently of the duk_hbufferobject if + * the underlying buffer is dynamic and changes without the hbufferobject + * being changed. + */ +#define DUK_HBUFFEROBJECT_FULL_SLICE(h) \ + (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ + ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf))) + +/* Validate that the whole slice [0,length[ is contained in the underlying + * buffer. Caller must ensure 'buf' != NULL. + */ +#define DUK_HBUFFEROBJECT_VALID_SLICE(h) \ + (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ + ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf))) + +/* Validate byte read/write for virtual 'offset', i.e. check that the + * offset, taking into account h->offset, is within the underlying + * buffer size. This is a safety check which is needed to ensure + * that even a misconfigured duk_hbufferobject never causes memory + * unsafe behavior (e.g. if an underlying dynamic buffer changes + * after being setup). Caller must ensure 'buf' != NULL. + */ +#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_INCL(h,off) \ + (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ + ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf))) + +#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h,off) \ + (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ + ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf))) + +/* Clamp an input byte length (already assumed to be within the nominal + * duk_hbufferobject 'length') to the current dynamic buffer limits to + * yield a byte length limit that's safe for memory accesses. This value + * can be invalidated by any side effect because it may trigger a user + * callback that resizes the underlying buffer. + */ +#define DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h,len) \ + (DUK_ASSERT_EXPR((h) != NULL), \ + duk_hbufferobject_clamp_bytelength((h), (len))) + +struct duk_hbufferobject { + /* Shared object part. */ + duk_hobject obj; + + /* Underlying buffer (refcounted), may be NULL. */ + duk_hbuffer *buf; + + /* Slice and accessor information. + * + * Because the underlying buffer may be dynamic, these may be + * invalidated by the buffer being modified so that both offset + * and length should be validated before every access. Behavior + * when the underlying buffer has changed doesn't need to be clean: + * virtual 'length' doesn't need to be affected, reads can return + * zero/NaN, and writes can be ignored. + * + * Note that a data pointer cannot be precomputed because 'buf' may + * be dynamic and its pointer unstable. + */ + + duk_uint_t offset; /* byte offset to buf */ + duk_uint_t length; /* byte index limit for element access, exclusive */ + duk_uint8_t shift; /* element size shift: + * 0 = u8/i8 + * 1 = u16/i16 + * 2 = u32/i32/float + * 3 = double + */ + duk_uint8_t elem_type; /* element type */ + duk_uint8_t is_view; +}; + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL_DECL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len); +#endif +DUK_INTERNAL_DECL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); +DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); + +#endif /* DUK_HBUFFEROBJECT_H_INCLUDED */ +/* + * Heap thread object representation. + * + * duk_hthread is also the 'context' (duk_context) for exposed APIs + * which mostly operate on the topmost frame of the value stack. + */ + +#ifndef DUK_HTHREAD_H_INCLUDED +#define DUK_HTHREAD_H_INCLUDED + +/* + * Stack constants + */ + +#define DUK_VALSTACK_GROW_STEP 128 /* roughly 1 kiB */ +#define DUK_VALSTACK_SHRINK_THRESHOLD 256 /* roughly 2 kiB */ +#define DUK_VALSTACK_SHRINK_SPARE 64 /* roughly 0.5 kiB */ +#define DUK_VALSTACK_INITIAL_SIZE 128 /* roughly 1.0 kiB -> but rounds up to DUK_VALSTACK_GROW_STEP in practice */ +#define DUK_VALSTACK_INTERNAL_EXTRA 64 /* internal extra elements assumed on function entry, + * always added to user-defined 'extra' for e.g. the + * duk_check_stack() call. + */ +#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK + /* number of elements guaranteed to be user accessible + * (in addition to call arguments) on Duktape/C function entry. + */ + +/* Note: DUK_VALSTACK_INITIAL_SIZE must be >= DUK_VALSTACK_API_ENTRY_MINIMUM + * + DUK_VALSTACK_INTERNAL_EXTRA so that the initial stack conforms to spare + * requirements. + */ + +#define DUK_VALSTACK_DEFAULT_MAX 1000000L + +#define DUK_CALLSTACK_GROW_STEP 8 /* roughly 256 bytes */ +#define DUK_CALLSTACK_SHRINK_THRESHOLD 16 /* roughly 512 bytes */ +#define DUK_CALLSTACK_SHRINK_SPARE 8 /* roughly 256 bytes */ +#define DUK_CALLSTACK_INITIAL_SIZE 8 +#define DUK_CALLSTACK_DEFAULT_MAX 10000L + +#define DUK_CATCHSTACK_GROW_STEP 4 /* roughly 64 bytes */ +#define DUK_CATCHSTACK_SHRINK_THRESHOLD 8 /* roughly 128 bytes */ +#define DUK_CATCHSTACK_SHRINK_SPARE 4 /* roughly 64 bytes */ +#define DUK_CATCHSTACK_INITIAL_SIZE 4 +#define DUK_CATCHSTACK_DEFAULT_MAX 10000L + +/* + * Activation defines + */ + +#define DUK_ACT_FLAG_STRICT (1 << 0) /* function executes in strict mode */ +#define DUK_ACT_FLAG_TAILCALLED (1 << 1) /* activation has tail called one or more times */ +#define DUK_ACT_FLAG_CONSTRUCT (1 << 2) /* function executes as a constructor (called via "new") */ +#define DUK_ACT_FLAG_PREVENT_YIELD (1 << 3) /* activation prevents yield (native call or "new") */ +#define DUK_ACT_FLAG_DIRECT_EVAL (1 << 4) /* activation is a direct eval call */ +#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1 << 5) /* activation has active breakpoint(s) */ + +#define DUK_ACT_GET_FUNC(act) ((act)->func) + +/* + * Flags for __FILE__ / __LINE__ registered into tracedata + */ + +#define DUK_TB_FLAG_NOBLAME_FILELINE (1 << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */ + +/* + * Catcher defines + */ + +/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */ +#define DUK_CAT_TYPE_MASK 0x0000000fUL +#define DUK_CAT_TYPE_BITS 4 +#define DUK_CAT_LABEL_MASK 0xffffff00UL +#define DUK_CAT_LABEL_BITS 24 +#define DUK_CAT_LABEL_SHIFT 8 + +#define DUK_CAT_FLAG_CATCH_ENABLED (1 << 4) /* catch part will catch */ +#define DUK_CAT_FLAG_FINALLY_ENABLED (1 << 5) /* finally part will catch */ +#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1 << 6) /* request to create catch binding */ +#define DUK_CAT_FLAG_LEXENV_ACTIVE (1 << 7) /* catch or with binding is currently active */ + +#define DUK_CAT_TYPE_UNKNOWN 0 +#define DUK_CAT_TYPE_TCF 1 +#define DUK_CAT_TYPE_LABEL 2 + +#define DUK_CAT_GET_TYPE(c) ((c)->flags & DUK_CAT_TYPE_MASK) +#define DUK_CAT_GET_LABEL(c) (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT) + +#define DUK_CAT_HAS_CATCH_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED) +#define DUK_CAT_HAS_FINALLY_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED) +#define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED) +#define DUK_CAT_HAS_LEXENV_ACTIVE(c) ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE) + +#define DUK_CAT_SET_CATCH_ENABLED(c) do { \ + (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \ + } while (0) +#define DUK_CAT_SET_FINALLY_ENABLED(c) do { \ + (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \ + } while (0) +#define DUK_CAT_SET_CATCH_BINDING_ENABLED(c) do { \ + (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \ + } while (0) +#define DUK_CAT_SET_LEXENV_ACTIVE(c) do { \ + (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \ + } while (0) + +#define DUK_CAT_CLEAR_CATCH_ENABLED(c) do { \ + (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \ + } while (0) +#define DUK_CAT_CLEAR_FINALLY_ENABLED(c) do { \ + (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \ + } while (0) +#define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c) do { \ + (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \ + } while (0) +#define DUK_CAT_CLEAR_LEXENV_ACTIVE(c) do { \ + (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \ + } while (0) + +/* + * Thread defines + */ + +#if defined(DUK_USE_ROM_STRINGS) +#define DUK_HTHREAD_GET_STRING(thr,idx) \ + ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)])) +#else /* DUK_USE_ROM_STRINGS */ +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HTHREAD_GET_STRING(thr,idx) \ + ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((thr)->heap->heap_udata, (thr)->strs16[(idx)])) +#else +#define DUK_HTHREAD_GET_STRING(thr,idx) \ + ((thr)->strs[(idx)]) +#endif +#endif /* DUK_USE_ROM_STRINGS */ + +#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1]) + +/* values for the state field */ +#define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */ +#define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */ +#define DUK_HTHREAD_STATE_RESUMED 3 /* thread resumed another thread (active but not running) */ +#define DUK_HTHREAD_STATE_YIELDED 4 /* thread has yielded */ +#define DUK_HTHREAD_STATE_TERMINATED 5 /* thread has terminated */ + +/* Executor interrupt default interval when nothing else requires a + * smaller value. The default interval must be small enough to allow + * for reasonable execution timeout checking but large enough to keep + * impact on execution performance low. + */ +#if defined(DUK_USE_INTERRUPT_COUNTER) +#define DUK_HTHREAD_INTCTR_DEFAULT (256L * 1024L) +#endif + +/* + * Assert context is valid: non-NULL pointer, fields look sane. + * + * This is used by public API call entrypoints to catch invalid 'ctx' pointers + * as early as possible; invalid 'ctx' pointers cause very odd and difficult to + * diagnose behavior so it's worth checking even when the check is not 100%. + */ + +#if defined(DUK_USE_PREFER_SIZE) +#define DUK_ASSERT_CTX_VSSIZE(ctx) /*nop*/ +#else +#define DUK_ASSERT_CTX_VSSIZE(ctx) \ + DUK_ASSERT((duk_size_t) (((duk_hthread *) (ctx))->valstack_end - ((duk_hthread *) (ctx))->valstack) == \ + ((duk_hthread *) (ctx))->valstack_size) +#endif +#define DUK_ASSERT_CTX_VALID(ctx) do { \ + DUK_ASSERT((ctx) != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (ctx)) == DUK_HTYPE_OBJECT); \ + DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (ctx))); \ + DUK_ASSERT(((duk_hthread *) (ctx))->unused1 == 0); \ + DUK_ASSERT(((duk_hthread *) (ctx))->unused2 == 0); \ + DUK_ASSERT(((duk_hthread *) (ctx))->valstack != NULL); \ + DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack); \ + DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack); \ + DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack_bottom); \ + DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack_top); \ + DUK_ASSERT_CTX_VSSIZE((ctx)); \ + } while (0) + +/* + * Struct defines + */ + +/* XXX: for a memory-code tradeoff, remove 'func' and make it's access either a function + * or a macro. This would make the activation 32 bytes long on 32-bit platforms again. + */ + +/* Note: it's nice if size is 2^N (at least for 32-bit platforms). */ +struct duk_activation { + duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */ + duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */ + duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */ + duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */ +#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY + /* Previous value of 'func' caller, restored when unwound. Only in use + * when 'func' is non-strict. + */ + duk_hobject *prev_caller; +#endif + + duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */ +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_uint32_t prev_line; /* needed for stepping */ +#endif + duk_small_uint_t flags; + + /* idx_bottom and idx_retval are only used for book-keeping of + * Ecmascript-initiated calls, to allow returning to an Ecmascript + * function properly. They are duk_size_t to match the convention + * that value stack sizes are duk_size_t and local frame indices + * are duk_idx_t. + */ + + /* Bottom of valstack for this activation, used to reset + * valstack_bottom on return; index is absolute. Note: + * idx_top not needed because top is set to 'nregs' always + * when returning to an Ecmascript activation. + */ + duk_size_t idx_bottom; + + /* Return value when returning to this activation (points to caller + * reg, not callee reg); index is absolute (only set if activation is + * not topmost). + * + * Note: idx_bottom is always set, while idx_retval is only applicable + * for activations below the topmost one. Currently idx_retval for + * the topmost activation is considered garbage (and it not initialized + * on entry or cleared on return; may contain previous or garbage + * values). + */ + duk_size_t idx_retval; + + /* Current 'this' binding is the value just below idx_bottom. + * Previously, 'this' binding was handled with an index to the + * (calling) valstack. This works for everything except tail + * calls, which must not "cumulate" valstack temps. + */ +}; + +/* Note: it's nice if size is 2^N (not 4x4 = 16 bytes on 32 bit) */ +struct duk_catcher { + duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */ + /* (reference is valid as long activation exists) */ + duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */ + duk_size_t callstack_index; /* callstack index of related activation */ + duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */ + duk_uint32_t flags; /* type and control flags, label number */ +}; + +struct duk_hthread { + /* Shared object part */ + duk_hobject obj; + + /* Pointer to bytecode executor's 'curr_pc' variable. Used to copy + * the current PC back into the topmost activation when activation + * state is about to change (or "syncing" is otherwise needed). This + * is rather awkward but important for performance, see execution.rst. + */ + duk_instr_t **ptr_curr_pc; + + /* Backpointers. */ + duk_heap *heap; + + /* Current strictness flag: affects API calls. */ + duk_uint8_t strict; + + /* Thread state. */ + duk_uint8_t state; + duk_uint8_t unused1; + duk_uint8_t unused2; + + /* Sanity limits for stack sizes. */ + duk_size_t valstack_max; + duk_size_t callstack_max; + duk_size_t catchstack_max; + + /* XXX: Valstack, callstack, and catchstack are currently assumed + * to have non-NULL pointers. Relaxing this would not lead to big + * benefits (except perhaps for terminated threads). + */ + + /* Value stack: these are expressed as pointers for faster stack manipulation. + * [valstack,valstack_top[ is GC-reachable, [valstack_top,valstack_end[ is + * not GC-reachable but kept initialized as 'undefined'. + */ + duk_tval *valstack; /* start of valstack allocation */ + duk_tval *valstack_end; /* end of valstack allocation (exclusive) */ + duk_tval *valstack_bottom; /* bottom of current frame */ + duk_tval *valstack_top; /* top of current frame (exclusive) */ +#if !defined(DUK_USE_PREFER_SIZE) + duk_size_t valstack_size; /* cached: valstack_end - valstack (in entries, not bytes) */ +#endif + + /* Call stack. [0,callstack_top[ is GC reachable. */ + duk_activation *callstack; + duk_size_t callstack_size; /* allocation size */ + duk_size_t callstack_top; /* next to use, highest used is top - 1 */ + duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */ + + /* Catch stack. [0,catchstack_top[ is GC reachable. */ + duk_catcher *catchstack; + duk_size_t catchstack_size; /* allocation size */ + duk_size_t catchstack_top; /* next to use, highest used is top - 1 */ + + /* Yield/resume book-keeping. */ + duk_hthread *resumer; /* who resumed us (if any) */ + + /* Current compiler state (if any), used for augmenting SyntaxErrors. */ + duk_compiler_ctx *compile_ctx; + +#if defined(DUK_USE_INTERRUPT_COUNTER) + /* Interrupt counter for triggering a slow path check for execution + * timeout, debugger interaction such as breakpoints, etc. The value + * is valid for the current running thread, and both the init and + * counter values are copied whenever a thread switch occurs. It's + * important for the counter to be conveniently accessible for the + * bytecode executor inner loop for performance reasons. + */ + duk_int_t interrupt_counter; /* countdown state */ + duk_int_t interrupt_init; /* start value for current countdown */ +#endif + + /* Builtin-objects; may or may not be shared with other threads, + * threads existing in different "compartments" will have different + * built-ins. Must be stored on a per-thread basis because there + * is no intermediate structure for a thread group / compartment. + * This takes quite a lot of space, currently 43x4 = 172 bytes on + * 32-bit platforms. + * + * In some cases the builtins array could be ROM based, but it's + * sometimes edited (e.g. for sandboxing) so it's better to keep + * this array in RAM. + */ + duk_hobject *builtins[DUK_NUM_BUILTINS]; + + /* Convenience copies from heap/vm for faster access. */ +#if defined(DUK_USE_ROM_STRINGS) + /* No field needed when strings are in ROM. */ +#else +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t *strs16; +#else + duk_hstring **strs; +#endif +#endif +}; + +/* + * Prototypes + */ + +DUK_INTERNAL_DECL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to); +DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr); +DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr); + +DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top); +DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top); + +DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr); +DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ +DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ +DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ + +#if defined(DUK_USE_DEBUGGER_SUPPORT) +DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act); +#endif +DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act); +DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr); + +#endif /* DUK_HTHREAD_H_INCLUDED */ +/* + * Heap buffer representation. + * + * Heap allocated user data buffer which is either: + * + * 1. A fixed size buffer (data follows header statically) + * 2. A dynamic size buffer (data pointer follows header) + * + * The data pointer for a variable size buffer of zero size may be NULL. + */ + +#ifndef DUK_HBUFFER_H_INCLUDED +#define DUK_HBUFFER_H_INCLUDED + +/* + * Flags + * + * Fixed buffer: 0 + * Dynamic buffer: DUK_HBUFFER_FLAG_DYNAMIC + * External buffer: DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL + */ + +#define DUK_HBUFFER_FLAG_DYNAMIC DUK_HEAPHDR_USER_FLAG(0) /* buffer is behind a pointer, dynamic or external */ +#define DUK_HBUFFER_FLAG_EXTERNAL DUK_HEAPHDR_USER_FLAG(1) /* buffer pointer is to an externally allocated buffer */ + +#define DUK_HBUFFER_HAS_DYNAMIC(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC) +#define DUK_HBUFFER_HAS_EXTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL) + +#define DUK_HBUFFER_SET_DYNAMIC(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC) +#define DUK_HBUFFER_SET_EXTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL) + +#define DUK_HBUFFER_CLEAR_DYNAMIC(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC) +#define DUK_HBUFFER_CLEAR_EXTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL) + +/* + * Misc defines + */ + +/* Impose a maximum buffer length for now. Restricted artificially to + * ensure resize computations or adding a heap header length won't + * overflow size_t and that a signed duk_int_t can hold a buffer + * length. The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN. + */ + +#if defined(DUK_USE_BUFLEN16) +#define DUK_HBUFFER_MAX_BYTELEN (0x0000ffffUL) +#else +/* Intentionally not 0x7fffffffUL; at least JSON code expects that + * 2*len + 2 fits in 32 bits. + */ +#define DUK_HBUFFER_MAX_BYTELEN (0x7ffffffeUL) +#endif + +/* + * Field access + */ + +/* Get/set the current user visible size, without accounting for a dynamic + * buffer's "spare" (= usable size). + */ +#if defined(DUK_USE_BUFLEN16) +/* size stored in duk_heaphdr unused flag bits */ +#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16) +#define DUK_HBUFFER_SET_SIZE(x,v) do { \ + duk_size_t duk__v; \ + duk__v = (v); \ + DUK_ASSERT(duk__v <= 0xffffUL); \ + (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \ + } while (0) +#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \ + (x)->hdr.h_flags += ((dv) << 16); \ + } while (0) +#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \ + (x)->hdr.h_flags -= ((dv) << 16); \ + } while (0) +#else +#define DUK_HBUFFER_GET_SIZE(x) (((duk_hbuffer *) (x))->size) +#define DUK_HBUFFER_SET_SIZE(x,v) do { \ + ((duk_hbuffer *) (x))->size = (v); \ + } while (0) +#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \ + (x)->size += (dv); \ + } while (0) +#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \ + (x)->size -= (dv); \ + } while (0) +#endif + +#define DUK_HBUFFER_FIXED_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) +#define DUK_HBUFFER_FIXED_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x)) + +#define DUK_HBUFFER_DYNAMIC_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) +#define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v)) +#define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv) DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv)) +#define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv) DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv)) + +#define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) +#define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v)) + +#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (x)) + 1)) + +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \ + ((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16)) +#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \ + ((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ + } while (0) +#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \ + ((duk_heaphdr *) (x))->h_extra16 = 0; /* assume 0 <=> NULL */ \ + } while (0) +#else +#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) ((x)->curr_alloc) +#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \ + (x)->curr_alloc = (void *) (v); \ + } while (0) +#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \ + (x)->curr_alloc = (void *) NULL; \ + } while (0) +#endif + +/* No pointer compression because pointer is potentially outside of + * Duktape heap. + */ +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \ + ((void *) (x)->curr_alloc) +#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \ + (x)->curr_alloc = (void *) (v); \ + } while (0) +#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \ + (x)->curr_alloc = (void *) NULL; \ + } while (0) +#else +#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \ + ((void *) (x)->curr_alloc) +#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \ + (x)->curr_alloc = (void *) (v); \ + } while (0) +#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \ + (x)->curr_alloc = (void *) NULL; \ + } while (0) +#endif + +/* Get a pointer to the current buffer contents (matching current allocation + * size). May be NULL for zero size dynamic/external buffer. + */ +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \ + DUK_HBUFFER_HAS_DYNAMIC((x)) ? \ + ( \ + DUK_HBUFFER_HAS_EXTERNAL((x)) ? \ + DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \ + DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \ + ) : \ + DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \ + ) +#else +/* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external + * have the same layout so checking for fixed vs. dynamic (or external) is enough. + */ +#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \ + DUK_HBUFFER_HAS_DYNAMIC((x)) ? \ + DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \ + DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \ + ) +#endif + +/* + * Structs + */ + +/* Shared prefix for all buffer types. */ +struct duk_hbuffer { + duk_heaphdr hdr; + + /* It's not strictly necessary to track the current size, but + * it is useful for writing robust native code. + */ + + /* Current size (not counting a dynamic buffer's "spare"). */ +#if defined(DUK_USE_BUFLEN16) + /* Stored in duk_heaphdr unused flags. */ +#else + duk_size_t size; +#endif + + /* + * Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC + * flag. + * + * If the flag is clear (the buffer is a fixed size one), the buffer + * data follows the header directly, consisting of 'size' bytes. + * + * If the flag is set, the actual buffer is allocated separately, and + * a few control fields follow the header. Specifically: + * + * - a "void *" pointing to the current allocation + * - a duk_size_t indicating the full allocated size (always >= 'size') + * + * If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated + * by user code, so that Duktape won't be able to resize it and won't + * free it. This allows buffers to point to e.g. an externally + * allocated structure such as a frame buffer. + * + * Unlike strings, no terminator byte (NUL) is guaranteed after the + * data. This would be convenient, but would pad aligned user buffers + * unnecessarily upwards in size. For instance, if user code requested + * a 64-byte dynamic buffer, 65 bytes would actually be allocated which + * would then potentially round upwards to perhaps 68 or 72 bytes. + */ +}; + +/* Fixed buffer; data follows struct, with proper alignment guaranteed by + * struct size. + */ +#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA) +#pragma pack(push, 8) +#endif +struct duk_hbuffer_fixed { + /* A union is used here as a portable struct size / alignment trick: + * by adding a 32-bit or a 64-bit (unused) union member, the size of + * the struct is effectively forced to be a multiple of 4 or 8 bytes + * (respectively) without increasing the size of the struct unless + * necessary. + */ + union { + struct { + duk_heaphdr hdr; +#if defined(DUK_USE_BUFLEN16) + /* Stored in duk_heaphdr unused flags. */ +#else + duk_size_t size; +#endif + } s; +#if (DUK_USE_ALIGN_BY == 4) + duk_uint32_t dummy_for_align4; +#elif (DUK_USE_ALIGN_BY == 8) + duk_double_t dummy_for_align8; +#elif (DUK_USE_ALIGN_BY == 1) + /* no extra padding */ +#else +#error invalid DUK_USE_ALIGN_BY +#endif + } u; + + /* + * Data follows the struct header. The struct size is padded by the + * compiler based on the struct members. This guarantees that the + * buffer data will be aligned-by-4 but not necessarily aligned-by-8. + * + * On platforms where alignment does not matter, the struct padding + * could be removed (if there is any). On platforms where alignment + * by 8 is required, the struct size must be forced to be a multiple + * of 8 by some means. Without it, some user code may break, and also + * Duktape itself breaks (e.g. the compiler stores duk_tvals in a + * dynamic buffer). + */ +} +#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR) +__attribute__ ((aligned (8))) +#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR) +__attribute__ ((aligned (8))) +#endif +; +#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA) +#pragma pack(pop) +#endif + +/* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using + * heap allocation primitives. Also used for external buffers when low memory + * options are not used. + */ +struct duk_hbuffer_dynamic { + duk_heaphdr hdr; + +#if defined(DUK_USE_BUFLEN16) + /* Stored in duk_heaphdr unused flags. */ +#else + duk_size_t size; +#endif + +#if defined(DUK_USE_HEAPPTR16) + /* Stored in duk_heaphdr h_extra16. */ +#else + void *curr_alloc; /* may be NULL if alloc_size == 0 */ +#endif + + /* + * Allocation size for 'curr_alloc' is alloc_size. There is no + * automatic NUL terminator for buffers (see above for rationale). + * + * 'curr_alloc' is explicitly allocated with heap allocation + * primitives and will thus always have alignment suitable for + * e.g. duk_tval and an IEEE double. + */ +}; + +/* External buffer with 'curr_alloc' managed by user code and pointing to an + * arbitrary address. When heap pointer compression is not used, this struct + * has the same layout as duk_hbuffer_dynamic. + */ +struct duk_hbuffer_external { + duk_heaphdr hdr; + +#if defined(DUK_USE_BUFLEN16) + /* Stored in duk_heaphdr unused flags. */ +#else + duk_size_t size; +#endif + + /* Cannot be compressed as a heap pointer because may point to + * an arbitrary address. + */ + void *curr_alloc; /* may be NULL if alloc_size == 0 */ +}; + +/* + * Prototypes + */ + +DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata); +DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud); /* indirect allocs */ + +/* dynamic buffer ops */ +DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size); +DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf); + +#endif /* DUK_HBUFFER_H_INCLUDED */ +/* + * Heap structure. + * + * Heap contains allocated heap objects, interned strings, and built-in + * strings for one or more threads. + */ + +#ifndef DUK_HEAP_H_INCLUDED +#define DUK_HEAP_H_INCLUDED + +/* alloc function typedefs in duktape.h */ + +/* + * Heap flags + */ + +#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */ +#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ +#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */ +#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */ +#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */ +#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */ + +#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits)) +#define DUK__HEAP_SET_FLAGS(heap,bits) do { \ + (heap)->flags |= (bits); \ + } while (0) +#define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \ + (heap)->flags &= ~(bits); \ + } while (0) + +#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) +#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) +#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) +#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) +#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) +#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) + +#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) +#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) +#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) +#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) +#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) +#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) + +#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) +#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) +#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) +#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) +#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) +#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) + +/* + * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally') + */ + +#define DUK_LJ_TYPE_UNKNOWN 0 /* unused */ +#define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */ +#define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */ +#define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */ +#define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */ +#define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */ +#define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */ +#define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */ + +/* + * Mark-and-sweep flags + * + * These are separate from heap level flags now but could be merged. + * The heap structure only contains a 'base mark-and-sweep flags' + * field and the GC caller can impose further flags. + */ + +#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */ +#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */ +#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */ +#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */ +#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */ + +/* + * Thread switching + * + * To switch heap->curr_thread, use the macro below so that interrupt counters + * get updated correctly. The macro allows a NULL target thread because that + * happens e.g. in call handling. + */ + +#if defined(DUK_USE_INTERRUPT_COUNTER) +#define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr)) +#else +#define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \ + (heap)->curr_thread = (newthr); \ + } while (0) +#endif + +/* + * Other heap related defines + */ + +/* Mark-and-sweep interval is relative to combined count of objects and + * strings kept in the heap during the latest mark-and-sweep pass. + * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is + * decreased by each (re)allocation attempt (regardless of size), and each + * refzero processed object. + * + * 'SKIP' indicates how many (re)allocations to wait until a retry if + * GC is skipped because there is no thread do it with yet (happens + * only during init phases). + */ +#if defined(DUK_USE_MARK_AND_SWEEP) +#if defined(DUK_USE_REFERENCE_COUNTING) +#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */ +#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L +#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L +#else +#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */ +#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L +#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L +#endif +#endif + +/* Stringcache is used for speeding up char-offset-to-byte-offset + * translations for non-ASCII strings. + */ +#define DUK_HEAP_STRCACHE_SIZE 4 +#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */ + +/* helper to insert a (non-string) heap object into heap allocated list */ +#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr)) + +/* + * Stringtable + */ + +/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */ +#define DUK_STRTAB_INITIAL_SIZE 17 + +/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */ +#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap) + +/* resizing parameters */ +#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */ +#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */ +#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */ + +#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ +#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL + +/* probe sequence (open addressing) */ +#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) +#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) + +/* fixed top level hashtable size (separate chaining) */ +#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE + +/* + * Built-in strings + */ + +/* heap string indices are autogenerated in duk_strings.h */ +#if defined(DUK_USE_ROM_STRINGS) +#define DUK_HEAP_GET_STRING(heap,idx) \ + ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)])) +#else /* DUK_USE_ROM_STRINGS */ +#if defined(DUK_USE_HEAPPTR16) +#define DUK_HEAP_GET_STRING(heap,idx) \ + ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)])) +#else +#define DUK_HEAP_GET_STRING(heap,idx) \ + ((heap)->strs[(idx)]) +#endif +#endif /* DUK_USE_ROM_STRINGS */ + +/* + * Raw memory calls: relative to heap, but no GC interaction + */ + +#define DUK_ALLOC_RAW(heap,size) \ + ((heap)->alloc_func((heap)->heap_udata, (size))) + +#define DUK_REALLOC_RAW(heap,ptr,newsize) \ + ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize))) + +#define DUK_FREE_RAW(heap,ptr) \ + ((heap)->free_func((heap)->heap_udata, (void *) (ptr))) + +/* + * Memory calls: relative to heap, GC interaction, but no error throwing. + * + * XXX: Currently a mark-and-sweep triggered by memory allocation will run + * using the heap->heap_thread. This thread is also used for running + * mark-and-sweep finalization; this is not ideal because it breaks the + * isolation between multiple global environments. + * + * Notes: + * + * - DUK_FREE() is required to ignore NULL and any other possible return + * value of a zero-sized alloc/realloc (same as ANSI C free()). + * + * - There is no DUK_REALLOC_ZEROED because we don't assume to know the + * old size. Caller must zero the reallocated memory. + * + * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered + * by an allocation failure might invalidate the original 'ptr', thus + * causing a realloc retry to use an invalid pointer. Example: we're + * reallocating the value stack and a finalizer resizes the same value + * stack during mark-and-sweep. The indirect variant requests for the + * current location of the pointer being reallocated using a callback + * right before every realloc attempt; this circuitous approach is used + * to avoid strict aliasing issues in a more straightforward indirect + * pointer (void **) approach. Note: the pointer in the storage + * location is read but is NOT updated; the caller must do that. + */ + +/* callback for indirect reallocs, request for current pointer */ +typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud); + +#define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size)) +#define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size)) +#define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize)) +#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize)) +#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr)) + +/* + * Memory constants + */ + +#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this + * many times. A single mark-and-sweep round is + * not guaranteed to free all unreferenced memory + * because of finalization (in fact, ANY number of + * rounds is strictly not enough). + */ + +#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode + * for mark-and-sweep. + */ + +/* + * Debugger support + */ + +/* Maximum number of breakpoints. Only breakpoints that are set are + * consulted so increasing this has no performance impact. + */ +#define DUK_HEAP_MAX_BREAKPOINTS 16 + +/* Opcode interval for a Date-based status/peek rate limit check. Only + * relevant when debugger is attached. Requesting a timestamp may be a + * slow operation on some platforms so this shouldn't be too low. On the + * other hand a high value makes Duktape react to a pause request slowly. + */ +#define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000 + +/* Milliseconds between status notify and transport peeks. */ +#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200 + +/* Step types */ +#define DUK_STEP_TYPE_NONE 0 +#define DUK_STEP_TYPE_INTO 1 +#define DUK_STEP_TYPE_OVER 2 +#define DUK_STEP_TYPE_OUT 3 + +struct duk_breakpoint { + duk_hstring *filename; + duk_uint32_t line; +}; + +#if defined(DUK_USE_DEBUGGER_SUPPORT) +#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL) +#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \ + (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \ + (heap)->dbg_step_thread = NULL; \ + (heap)->dbg_step_csindex = 0; \ + (heap)->dbg_step_startline = 0; \ + } while (0) +#define DUK_HEAP_SET_PAUSED(heap) do { \ + (heap)->dbg_paused = 1; \ + (heap)->dbg_state_dirty = 1; \ + DUK_HEAP_CLEAR_STEP_STATE((heap)); \ + } while (0) +#define DUK_HEAP_CLEAR_PAUSED(heap) do { \ + (heap)->dbg_paused = 0; \ + (heap)->dbg_state_dirty = 1; \ + DUK_HEAP_CLEAR_STEP_STATE((heap)); \ + } while (0) +#define DUK_HEAP_IS_PAUSED(heap) ((heap)->dbg_paused) +#endif /* DUK_USE_DEBUGGER_SUPPORT */ + +/* + * String cache should ideally be at duk_hthread level, but that would + * cause string finalization to slow down relative to the number of + * threads; string finalization must check the string cache for "weak" + * references to the string being finalized to avoid dead pointers. + * + * Thus, string caches are now at the heap level now. + */ + +struct duk_strcache { + duk_hstring *h; + duk_uint32_t bidx; + duk_uint32_t cidx; +}; + +/* + * Longjmp state, contains the information needed to perform a longjmp. + * Longjmp related values are written to value1, value2, and iserror. + */ + +struct duk_ljstate { + duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */ + duk_small_uint_t type; /* longjmp type */ + duk_bool_t iserror; /* isError flag for yield */ + duk_tval value1; /* 1st related value (type specific) */ + duk_tval value2; /* 2nd related value (type specific) */ +}; + +/* + * Stringtable entry for fixed size stringtable + */ + +struct duk_strtab_entry { +#if defined(DUK_USE_HEAPPTR16) + /* A 16-bit listlen makes sense with 16-bit heap pointers: there + * won't be space for 64k strings anyway. + */ + duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */ + union { + duk_uint16_t strlist16; + duk_uint16_t str16; + } u; +#else + duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */ + union { + duk_hstring **strlist; + duk_hstring *str; + } u; +#endif +}; + +/* + * Main heap structure + */ + +struct duk_heap { + duk_small_uint_t flags; + + /* Allocator functions. */ + duk_alloc_function alloc_func; + duk_realloc_function realloc_func; + duk_free_function free_func; + + /* Heap udata, used for allocator functions but also for other heap + * level callbacks like pointer compression, etc. + */ + void *heap_udata; + + /* Precomputed pointers when using 16-bit heap pointer packing. */ +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t heapptr_null16; + duk_uint16_t heapptr_deleted16; +#endif + + /* Fatal error handling, called e.g. when a longjmp() is needed but + * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not + * declared as "noreturn" because doing that for typedefs is a bit + * challenging portability-wise. + */ + duk_fatal_function fatal_func; + + /* allocated heap objects */ + duk_heaphdr *heap_allocated; + + /* work list for objects whose refcounts are zero but which have not been + * "finalized"; avoids recursive C calls when refcounts go to zero in a + * chain of objects. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + duk_heaphdr *refzero_list; + duk_heaphdr *refzero_list_tail; +#endif + +#if defined(DUK_USE_MARK_AND_SWEEP) + /* mark-and-sweep control */ +#if defined(DUK_USE_VOLUNTARY_GC) + duk_int_t mark_and_sweep_trigger_counter; +#endif + duk_int_t mark_and_sweep_recursion_depth; + + /* mark-and-sweep flags automatically active (used for critical sections) */ + duk_small_uint_t mark_and_sweep_base_flags; + + /* work list for objects to be finalized (by mark-and-sweep) */ + duk_heaphdr *finalize_list; +#endif + + /* longjmp state */ + duk_ljstate lj; + + /* marker for detecting internal "double faults", see duk_error_throw.c */ + duk_bool_t handling_error; + + /* heap thread, used internally and for finalization */ + duk_hthread *heap_thread; + + /* current thread */ + duk_hthread *curr_thread; /* currently running thread */ + + /* heap level "stash" object (e.g., various reachability roots) */ + duk_hobject *heap_object; + + /* duk_handle_call / duk_handle_safe_call recursion depth limiting */ + duk_int_t call_recursion_depth; + duk_int_t call_recursion_limit; + + /* mix-in value for computing string hashes; should be reasonably unpredictable */ + duk_uint32_t hash_seed; + + /* rnd_state for duk_util_tinyrandom.c */ + duk_uint32_t rnd_state; + + /* For manual debugging: instruction count based on executor and + * interrupt counter book-keeping. Inspect debug logs to see how + * they match up. + */ +#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) + duk_int_t inst_count_exec; + duk_int_t inst_count_interrupt; +#endif + + /* debugger */ + +#if defined(DUK_USE_DEBUGGER_SUPPORT) + /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */ + duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */ + duk_debug_write_function dbg_write_cb; /* required */ + duk_debug_peek_function dbg_peek_cb; + duk_debug_read_flush_function dbg_read_flush_cb; + duk_debug_write_flush_function dbg_write_flush_cb; + duk_debug_request_function dbg_request_cb; + duk_debug_detached_function dbg_detached_cb; + void *dbg_udata; + + /* debugger state, only relevant when attached */ + duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */ + duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */ + duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */ + duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */ + duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */ + duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */ + duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */ + duk_size_t dbg_step_csindex; /* callstack index */ + duk_uint32_t dbg_step_startline; /* starting line number */ + duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */ + duk_small_uint_t dbg_breakpoint_count; + duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */ + /* XXX: make active breakpoints actual copies instead of pointers? */ + + /* These are for rate limiting Status notifications and transport peeking. */ + duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */ + duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */ + duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */ + + /* Used to support single-byte stream lookahead. */ + duk_bool_t dbg_have_next_byte; + duk_uint8_t dbg_next_byte; +#endif + + /* string intern table (weak refs) */ +#if defined(DUK_USE_STRTAB_PROBE) +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t *strtable16; +#else + duk_hstring **strtable; +#endif + duk_uint32_t st_size; /* alloc size in elements */ + duk_uint32_t st_used; /* used elements (includes DELETED) */ +#endif + + /* XXX: static alloc is OK until separate chaining stringtable + * resizing is implemented. + */ +#if defined(DUK_USE_STRTAB_CHAIN) + duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE]; +#endif + + /* string access cache (codepoint offset -> byte offset) for fast string + * character looping; 'weak' reference which needs special handling in GC. + */ + duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]; + + /* built-in strings */ +#if defined(DUK_USE_ROM_STRINGS) + /* No field needed when strings are in ROM. */ +#else +#if defined(DUK_USE_HEAPPTR16) + duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS]; +#else + duk_hstring *strs[DUK_HEAP_NUM_STRINGS]; +#endif +#endif +}; + +/* + * Prototypes + */ + +DUK_INTERNAL_DECL +duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, + duk_realloc_function realloc_func, + duk_free_function free_func, + void *heap_udata, + duk_fatal_function fatal_func); +DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap); +DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h); +DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h); +DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr); + +DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); +#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) +DUK_INTERNAL_DECL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); +#endif +#if defined(DUK_USE_INTERRUPT_COUNTER) +DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr); +#endif + +#if 0 /*unused*/ +DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); +#endif +DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); +DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); +#if 0 /*unused*/ +DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val); +#endif +DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val); +DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); +#if defined(DUK_USE_REFERENCE_COUNTING) +DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h); +#endif +#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE) +DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap); +#endif +DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap); +#if defined(DUK_USE_DEBUG) +DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap); +#endif + + +DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h); +DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset); + +#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) +DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size); +DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize); +DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr); +#endif + +DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size); +DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size); +DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize); +DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize); +DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr); + +#ifdef DUK_USE_REFERENCE_COUNTING +#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); +#endif +#if 0 /* unused */ +DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv); +#endif +DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); +#if 0 /* unused */ +DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv); +#endif +#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); +#endif +#if 0 /* unused */ +DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h); +#endif +DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr); +#else +/* no refcounting */ +#endif + +#if defined(DUK_USE_MARK_AND_SWEEP) +DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); +#endif + +DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len); + +#endif /* DUK_HEAP_H_INCLUDED */ +#ifndef DUK_DEBUGGER_H_INCLUDED +#define DUK_DEBUGGER_H_INCLUDED + +/* Debugger protocol version is defined in the public API header. */ + +/* Initial bytes for markers. */ +#define DUK_DBG_IB_EOM 0x00 +#define DUK_DBG_IB_REQUEST 0x01 +#define DUK_DBG_IB_REPLY 0x02 +#define DUK_DBG_IB_ERROR 0x03 +#define DUK_DBG_IB_NOTIFY 0x04 + +/* Other initial bytes. */ +#define DUK_DBG_IB_INT4 0x10 +#define DUK_DBG_IB_STR4 0x11 +#define DUK_DBG_IB_STR2 0x12 +#define DUK_DBG_IB_BUF4 0x13 +#define DUK_DBG_IB_BUF2 0x14 +#define DUK_DBG_IB_UNUSED 0x15 +#define DUK_DBG_IB_UNDEFINED 0x16 +#define DUK_DBG_IB_NULL 0x17 +#define DUK_DBG_IB_TRUE 0x18 +#define DUK_DBG_IB_FALSE 0x19 +#define DUK_DBG_IB_NUMBER 0x1a +#define DUK_DBG_IB_OBJECT 0x1b +#define DUK_DBG_IB_POINTER 0x1c +#define DUK_DBG_IB_LIGHTFUNC 0x1d +#define DUK_DBG_IB_HEAPPTR 0x1e +/* The short string/integer initial bytes starting from 0x60 don't have + * defines now. + */ + +/* Error codes. */ +#define DUK_DBG_ERR_UNKNOWN 0x00 +#define DUK_DBG_ERR_UNSUPPORTED 0x01 +#define DUK_DBG_ERR_TOOMANY 0x02 +#define DUK_DBG_ERR_NOTFOUND 0x03 +#define DUK_DBG_ERR_APPLICATION 0x04 + +/* Commands and notifys initiated by Duktape. */ +#define DUK_DBG_CMD_STATUS 0x01 +#define DUK_DBG_CMD_PRINT 0x02 +#define DUK_DBG_CMD_ALERT 0x03 +#define DUK_DBG_CMD_LOG 0x04 +#define DUK_DBG_CMD_THROW 0x05 +#define DUK_DBG_CMD_DETACHING 0x06 +#define DUK_DBG_CMD_APPNOTIFY 0x07 + +/* Commands initiated by debug client. */ +#define DUK_DBG_CMD_BASICINFO 0x10 +#define DUK_DBG_CMD_TRIGGERSTATUS 0x11 +#define DUK_DBG_CMD_PAUSE 0x12 +#define DUK_DBG_CMD_RESUME 0x13 +#define DUK_DBG_CMD_STEPINTO 0x14 +#define DUK_DBG_CMD_STEPOVER 0x15 +#define DUK_DBG_CMD_STEPOUT 0x16 +#define DUK_DBG_CMD_LISTBREAK 0x17 +#define DUK_DBG_CMD_ADDBREAK 0x18 +#define DUK_DBG_CMD_DELBREAK 0x19 +#define DUK_DBG_CMD_GETVAR 0x1a +#define DUK_DBG_CMD_PUTVAR 0x1b +#define DUK_DBG_CMD_GETCALLSTACK 0x1c +#define DUK_DBG_CMD_GETLOCALS 0x1d +#define DUK_DBG_CMD_EVAL 0x1e +#define DUK_DBG_CMD_DETACH 0x1f +#define DUK_DBG_CMD_DUMPHEAP 0x20 +#define DUK_DBG_CMD_GETBYTECODE 0x21 +#define DUK_DBG_CMD_APPREQUEST 0x22 +#define DUK_DBG_CMD_GETHEAPOBJINFO 0x23 +#define DUK_DBG_CMD_GETOBJPROPDESC 0x24 +#define DUK_DBG_CMD_GETOBJPROPDESCRANGE 0x25 + +/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx. + * The remaining flags are specific to the debugger. + */ +#define DUK_DBG_PROPFLAG_INTERNAL (1 << 8) + +#if defined(DUK_USE_DEBUGGER_SUPPORT) +DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap); + +DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr); + +DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length); +DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr); + +DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length); +DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr); +DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr); +DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr); +/* XXX: exposed duk_debug_read_pointer */ +/* XXX: exposed duk_debug_read_buffer */ +/* XXX: exposed duk_debug_read_hbuffer */ +#if 0 +DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr); +#endif +#if defined(DUK_USE_DEBUGGER_INSPECT) +DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr); +#endif +DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr); + +DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length); +DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x); +DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr); +#if defined(DUK_USE_DEBUGGER_INSPECT) +DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr); +#endif +DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val); +DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x); +DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x); +DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length); +DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data); +DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length); +DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr); +#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT) +DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h); +#endif +DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj); +DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv); +#if 0 /* unused */ +DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command); +#endif +DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg); +DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command); +DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr); + +DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr); +#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) +DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal); +#endif + +DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc); +DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block); + +DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line); +DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index); +#endif + +#endif /* DUK_DEBUGGER_H_INCLUDED */ +/* + * Debugging macros, DUK_DPRINT() and its variants in particular. + * + * DUK_DPRINT() allows formatted debug prints, and supports standard + * and Duktape specific formatters. See duk_debug_vsnprintf.c for details. + * + * DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros + * for technical reasons. They are concretely used to hide 'x' from the + * compiler when the corresponding log level is disabled. This allows + * clean builds on non-C99 compilers, at the cost of more verbose code. + * Examples: + * + * DUK_D(DUK_DPRINT("foo")); + * DUK_DD(DUK_DDPRINT("foo")); + * DUK_DDD(DUK_DDDPRINT("foo")); + * + * This approach is preferable to the old "double parentheses" hack because + * double parentheses make the C99 solution worse: __FILE__ and __LINE__ can + * no longer be added transparently without going through globals, which + * works poorly with threading. + */ + +#ifndef DUK_DEBUG_H_INCLUDED +#define DUK_DEBUG_H_INCLUDED + +#ifdef DUK_USE_DEBUG + +#if defined(DUK_USE_DPRINT) +#define DUK_D(x) x +#else +#define DUK_D(x) do { } while (0) /* omit */ +#endif + +#if defined(DUK_USE_DDPRINT) +#define DUK_DD(x) x +#else +#define DUK_DD(x) do { } while (0) /* omit */ +#endif + +#if defined(DUK_USE_DDDPRINT) +#define DUK_DDD(x) x +#else +#define DUK_DDD(x) do { } while (0) /* omit */ +#endif + +/* + * Exposed debug macros: debugging enabled + */ + +#define DUK_LEVEL_DEBUG 1 +#define DUK_LEVEL_DDEBUG 2 +#define DUK_LEVEL_DDDEBUG 3 + +#ifdef DUK_USE_VARIADIC_MACROS + +/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be + * possible compile time, but waste some space with shared function names. + */ +#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_small_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__); + +#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__) + +#ifdef DUK_USE_DDPRINT +#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__) +#else +#define DUK_DDPRINT(...) +#endif + +#ifdef DUK_USE_DDDPRINT +#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__) +#else +#define DUK_DDDPRINT(...) +#endif + +#else /* DUK_USE_VARIADIC_MACROS */ + +#define DUK__DEBUG_STASH(lev) \ + (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \ + duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \ + (void) DUK_SNPRINTF(duk_debug_line_stash, DUK_DEBUG_STASH_SIZE, "%ld", (long) DUK_LINE_MACRO), \ + duk_debug_line_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \ + (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \ + duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \ + (void) (duk_debug_level_stash = (lev)) + +/* Without variadic macros resort to comma expression trickery to handle debug + * prints. This generates a lot of harmless warnings. These hacks are not + * needed normally because DUK_D() and friends will hide the entire debug log + * statement from the compiler. + */ + +#ifdef DUK_USE_DPRINT +#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */ +#else +#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */ +#endif + +#ifdef DUK_USE_DDPRINT +#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */ +#else +#define DUK_DDPRINT 0 && /* args */ +#endif + +#ifdef DUK_USE_DDDPRINT +#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */ +#else +#define DUK_DDDPRINT 0 && /* args */ +#endif + +#endif /* DUK_USE_VARIADIC_MACROS */ + +#else /* DUK_USE_DEBUG */ + +/* + * Exposed debug macros: debugging disabled + */ + +#define DUK_D(x) do { } while (0) /* omit */ +#define DUK_DD(x) do { } while (0) /* omit */ +#define DUK_DDD(x) do { } while (0) /* omit */ + +#ifdef DUK_USE_VARIADIC_MACROS + +#define DUK_DPRINT(...) +#define DUK_DDPRINT(...) +#define DUK_DDDPRINT(...) + +#else /* DUK_USE_VARIADIC_MACROS */ + +#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */ +#define DUK_DDPRINT 0 && /* args */ +#define DUK_DDDPRINT 0 && /* args */ + +#endif /* DUK_USE_VARIADIC_MACROS */ + +#endif /* DUK_USE_DEBUG */ + +/* + * Structs + */ + +#ifdef DUK_USE_DEBUG +struct duk_fixedbuffer { + duk_uint8_t *buffer; + duk_size_t length; + duk_size_t offset; + duk_bool_t truncated; +}; +#endif + +/* + * Prototypes + */ + +#ifdef DUK_USE_DEBUG +DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap); +#if 0 /*unused*/ +DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...); +#endif +DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size); + +#ifdef DUK_USE_VARIADIC_MACROS +DUK_INTERNAL_DECL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...); +#else /* DUK_USE_VARIADIC_MACROS */ +/* parameter passing, not thread safe */ +#define DUK_DEBUG_STASH_SIZE 128 +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE]; +DUK_INTERNAL_DECL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE]; +DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE]; +DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash; +#endif +DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...); +#endif /* DUK_USE_VARIADIC_MACROS */ + +DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length); +DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x); +DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x); +DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...); +DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size); +DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); + +#endif /* DUK_USE_DEBUG */ + +#endif /* DUK_DEBUG_H_INCLUDED */ +/* + * Error handling macros, assertion macro, error codes. + * + * There are three level of 'errors': + * + * 1. Ordinary errors, relative to a thread, cause a longjmp, catchable. + * 2. Fatal errors, relative to a heap, cause fatal handler to be called. + * 3. Panic errors, unrelated to a heap and cause a process exit. + * + * Panics are used by the default fatal error handler and by debug code + * such as assertions. By providing a proper fatal error handler, user + * code can avoid panics in non-debug builds. + */ + +#ifndef DUK_ERROR_H_INCLUDED +#define DUK_ERROR_H_INCLUDED + +/* + * Error codes: defined in duktape.h + * + * Error codes are used as a shorthand to throw exceptions from inside + * the implementation. The appropriate Ecmascript object is constructed + * based on the code. Ecmascript code throws objects directly. The error + * codes are defined in the public API header because they are also used + * by calling code. + */ + +/* + * Normal error + * + * Normal error is thrown with a longjmp() through the current setjmp() + * catchpoint record in the duk_heap. The 'curr_thread' of the duk_heap + * identifies the throwing thread. + * + * Error formatting is usually unnecessary. The error macros provide a + * zero argument version (no formatting) and separate macros for small + * argument counts. Variadic macros are not used to avoid portability + * issues and avoid the need for stash-based workarounds when they're not + * available. Vararg calls are avoided for non-formatted error calls + * because vararg call sites are larger than normal, and there are a lot + * of call sites with no formatting. + * + * Note that special formatting provided by debug macros is NOT available. + * + * The _RAW variants allow the caller to specify file and line. This makes + * it easier to write checked calls which want to use the call site of the + * checked function, not the error macro call inside the checked function. + */ + +#if defined(DUK_USE_VERBOSE_ERRORS) + +/* Because there are quite many call sites, pack error code (require at most + * 8-bit) into a single argument. + */ +#define DUK_ERROR(thr,err,msg) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \ + } while (0) +#define DUK_ERROR_RAW(thr,file,line,err,msg) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \ + } while (0) + +#define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \ + } while (0) +#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \ + } while (0) + +#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \ + } while (0) +#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \ + } while (0) + +#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \ + } while (0) +#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \ + } while (0) + +#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \ + } while (0) +#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \ + duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ + DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ + duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \ + } while (0) + +#else /* DUK_USE_VERBOSE_ERRORS */ + +#define DUK_ERROR(thr,err,msg) duk_err_handle_error((thr), (err)) +#define DUK_ERROR_RAW(thr,file,line,err,msg) duk_err_handle_error((thr), (err)) + +#define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt)) +#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) + +#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt)) +#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) + +#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt)) +#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) + +#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt)) +#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) + +#endif /* DUK_USE_VERBOSE_ERRORS */ + +/* + * Fatal error + * + * There are no fatal error macros at the moment. There are so few call + * sites that the fatal error handler is called directly. + */ + +/* + * Panic error + * + * Panic errors are not relative to either a heap or a thread, and cause + * DUK_PANIC() macro to be invoked. Unless a user provides DUK_USE_PANIC_HANDLER, + * DUK_PANIC() calls a helper which prints out the error and causes a process + * exit. + * + * The user can override the macro to provide custom handling. A macro is + * used to allow the user to have inline panic handling if desired (without + * causing a potentially risky function call). + * + * Panics are only used in debug code such as assertions, and by the default + * fatal error handler. + */ + +#if defined(DUK_USE_PANIC_HANDLER) +/* already defined, good */ +#define DUK_PANIC(code,msg) DUK_USE_PANIC_HANDLER((code),(msg)) +#else +#define DUK_PANIC(code,msg) duk_default_panic_handler((code),(msg)) +#endif /* DUK_USE_PANIC_HANDLER */ + +/* + * Assert macro: failure causes panic. + */ + +#if defined(DUK_USE_ASSERTIONS) + +/* the message should be a compile time constant without formatting (less risk); + * we don't care about assertion text size because they're not used in production + * builds. + */ +#define DUK_ASSERT(x) do { \ + if (!(x)) { \ + DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \ + "assertion failed: " #x \ + " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \ + } \ + } while (0) + +/* Assertion compatible inside a comma expression, evaluates to void. + * Currently not compatible with DUK_USE_PANIC_HANDLER() which may have + * a statement block. + */ +#if defined(DUK_USE_PANIC_HANDLER) +/* XXX: resolve macro definition issue or call through a helper function? */ +#define DUK_ASSERT_EXPR(x) ((void) 0) +#else +#define DUK_ASSERT_EXPR(x) \ + ((void) ((x) ? 0 : (DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \ + "assertion failed: " #x \ + " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0))) +#endif + +#else /* DUK_USE_ASSERTIONS */ + +#define DUK_ASSERT(x) do { /* assertion omitted */ } while (0) + +#define DUK_ASSERT_EXPR(x) ((void) 0) + +#endif /* DUK_USE_ASSERTIONS */ + +/* this variant is used when an assert would generate a compile warning by + * being always true (e.g. >= 0 comparison for an unsigned value + */ +#define DUK_ASSERT_DISABLE(x) do { /* assertion disabled */ } while (0) + +/* + * Assertion helpers + */ + +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) +#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) do { \ + DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \ + } while (0) +#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) do { \ + if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \ + } \ + } while (0) +#else +#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) /* no refcount check */ +#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) /* no refcount check */ +#endif + +#define DUK_ASSERT_TOP(ctx,n) DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n)) + +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL) +#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) do { \ + duk_double_union duk__assert_tmp_du; \ + duk__assert_tmp_du.d = (dval); \ + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \ + } while (0) +#else +#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */ +#endif + +/* + * Helper for valstack space + * + * Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries + * required for its own use, and any child calls which are not (a) Duktape API calls + * or (b) Duktape calls which involve extending the valstack (e.g. getter call). + */ + +#define DUK_VALSTACK_ASSERT_EXTRA 5 /* this is added to checks to allow for Duktape + * API calls in addition to function's own use + */ +#if defined(DUK_USE_ASSERTIONS) +#define DUK_ASSERT_VALSTACK_SPACE(thr,n) do { \ + DUK_ASSERT((thr) != NULL); \ + DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \ + } while (0) +#else +#define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */ +#endif + +/* + * Error throwing helpers + * + * The goal is to provide verbose and configurable error messages. Call + * sites should be clean in source code and compile to a small footprint. + * Small footprint is also useful for performance because small cold paths + * reduce code cache pressure. Adding macros here only makes sense if there + * are enough call sites to get concrete benefits. + */ + +#if defined(DUK_USE_VERBOSE_ERRORS) +/* Verbose errors with key/value summaries (non-paranoid) or without key/value + * summaries (paranoid, for some security sensitive environments), the paranoid + * vs. non-paranoid distinction affects only a few specific errors. + */ +#if defined(DUK_USE_PARANOID_ERRORS) +#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \ + duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \ + } while (0) +#else /* DUK_USE_PARANOID_ERRORS */ +#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \ + duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \ + } while (0) +#endif /* DUK_USE_PARANOID_ERRORS */ + +#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \ + DUK_ERROR((thr), DUK_ERR_UNIMPLEMENTED_ERROR, (msg)); \ + } while (0) +#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \ + duk_err_unimplemented_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ + } while (0) +#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \ + DUK_ERROR((thr), DUK_ERR_UNSUPPORTED_ERROR, (msg)); \ + } while (0) +#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT) +#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \ + duk_err_unsupported_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ + } while (0) +#endif +#define DUK_ERROR_INTERNAL(thr,msg) do { \ + duk_err_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ + } while (0) +#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \ + duk_err_internal_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ + } while (0) +#define DUK_ERROR_ALLOC(thr,msg) do { \ + duk_err_alloc((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ + } while (0) +#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \ + DUK_ERROR_ALLOC((thr), DUK_STR_ALLOC_FAILED); \ + } while (0) +/* DUK_ERR_ASSERTION_ERROR: no macros needed */ +#define DUK_ERROR_API_INDEX(thr,index) do { \ + duk_err_api_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index)); \ + } while (0) +#define DUK_ERROR_API(thr,msg) do { \ + duk_err_api((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ + } while (0) +/* DUK_ERR_UNCAUGHT_ERROR: no macros needed */ +/* DUK_ERR_ERROR: no macros needed */ +/* DUK_ERR_EVAL: no macros needed */ +#define DUK_ERROR_RANGE(thr,msg) do { \ + duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ + } while (0) +/* DUK_ERR_REFERENCE_ERROR: no macros needed */ +#define DUK_ERROR_SYNTAX(thr,msg) do { \ + DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \ + } while (0) +#define DUK_ERROR_TYPE(thr,msg) do { \ + DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \ + } while (0) +/* DUK_ERR_URI_ERROR: no macros needed */ +#else /* DUK_USE_VERBOSE_ERRORS */ +/* Non-verbose errors for low memory targets: no file, line, or message. */ + +#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \ + duk_err_type((thr)); \ + } while (0) + +#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \ + duk_err_unimplemented((thr)); \ + } while (0) +#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \ + duk_err_unimplemented((thr)); \ + } while (0) +#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \ + duk_err_unsupported((thr)); \ + } while (0) +#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \ + duk_err_unsupported((thr)); \ + } while (0) +#define DUK_ERROR_INTERNAL(thr,msg) do { \ + duk_err_internal((thr)); \ + } while (0) +#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \ + duk_err_internal((thr)); \ + } while (0) +#define DUK_ERROR_ALLOC(thr,msg) do { \ + duk_err_alloc((thr)); \ + } while (0) +#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \ + duk_err_alloc((thr)); \ + } while (0) +#define DUK_ERROR_API_INDEX(thr,index) do { \ + duk_err_api((thr)); \ + } while (0) +#define DUK_ERROR_API(thr,msg) do { \ + duk_err_api((thr)); \ + } while (0) +#define DUK_ERROR_RANGE(thr,msg) do { \ + duk_err_range((thr)); \ + } while (0) +#define DUK_ERROR_SYNTAX(thr,msg) do { \ + duk_err_syntax((thr)); \ + } while (0) +#define DUK_ERROR_TYPE(thr,msg) do { \ + duk_err_type((thr)); \ + } while (0) +#endif /* DUK_USE_VERBOSE_ERRORS */ + +/* + * Prototypes + */ + +#if defined(DUK_USE_VERBOSE_ERRORS) +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...)); +#else /* DUK_USE_VERBOSE_ERRORS */ +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code)); +#endif /* DUK_USE_VERBOSE_ERRORS */ + +#if defined(DUK_USE_VERBOSE_ERRORS) +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line)); +#else +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)); +#endif + +DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc)); + +#if defined(DUK_USE_AUGMENT_ERROR_CREATE) +DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_bool_t noblame_fileline); +#endif +#if defined(DUK_USE_AUGMENT_ERROR_THROW) +DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr); +#endif + +#if defined(DUK_USE_VERBOSE_ERRORS) +#if defined(DUK_USE_PARANOID_ERRORS) +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name)); +#else +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name)); +#endif +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber)); +#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT) +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber)); +#endif +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); +#else /* DUK_VERBOSE_ERRORS */ +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr)); +#endif /* DUK_VERBOSE_ERRORS */ + +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr)); + +DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg)); + +#if !defined(DUK_USE_PANIC_HANDLER) +DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_panic_handler(duk_errcode_t code, const char *msg)); +#endif + +DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type); + +DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code); + +#endif /* DUK_ERROR_H_INCLUDED */ +/* + * Unicode helpers + */ + +#ifndef DUK_UNICODE_H_INCLUDED +#define DUK_UNICODE_H_INCLUDED + +/* + * UTF-8 / XUTF-8 / CESU-8 constants + */ + +#define DUK_UNICODE_MAX_XUTF8_LENGTH 7 /* up to 36 bit codepoints */ +#define DUK_UNICODE_MAX_XUTF8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */ +#define DUK_UNICODE_MAX_CESU8_LENGTH 6 /* all codepoints up to U+10FFFF */ +#define DUK_UNICODE_MAX_CESU8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */ + +/* + * Useful Unicode codepoints + * + * Integer constants must be signed to avoid unexpected coercions + * in comparisons. + */ + +#define DUK_UNICODE_CP_ZWNJ 0x200cL /* zero-width non-joiner */ +#define DUK_UNICODE_CP_ZWJ 0x200dL /* zero-width joiner */ +#define DUK_UNICODE_CP_REPLACEMENT_CHARACTER 0xfffdL /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */ + +/* + * ASCII character constants + * + * C character literals like 'x' have a platform specific value and do + * not match ASCII (UTF-8) values on e.g. EBCDIC platforms. So, use + * these (admittedly awkward) constants instead. These constants must + * also have signed values to avoid unexpected coercions in comparisons. + * + * http://en.wikipedia.org/wiki/ASCII + */ + +#define DUK_ASC_NUL 0x00 +#define DUK_ASC_SOH 0x01 +#define DUK_ASC_STX 0x02 +#define DUK_ASC_ETX 0x03 +#define DUK_ASC_EOT 0x04 +#define DUK_ASC_ENQ 0x05 +#define DUK_ASC_ACK 0x06 +#define DUK_ASC_BEL 0x07 +#define DUK_ASC_BS 0x08 +#define DUK_ASC_HT 0x09 +#define DUK_ASC_LF 0x0a +#define DUK_ASC_VT 0x0b +#define DUK_ASC_FF 0x0c +#define DUK_ASC_CR 0x0d +#define DUK_ASC_SO 0x0e +#define DUK_ASC_SI 0x0f +#define DUK_ASC_DLE 0x10 +#define DUK_ASC_DC1 0x11 +#define DUK_ASC_DC2 0x12 +#define DUK_ASC_DC3 0x13 +#define DUK_ASC_DC4 0x14 +#define DUK_ASC_NAK 0x15 +#define DUK_ASC_SYN 0x16 +#define DUK_ASC_ETB 0x17 +#define DUK_ASC_CAN 0x18 +#define DUK_ASC_EM 0x19 +#define DUK_ASC_SUB 0x1a +#define DUK_ASC_ESC 0x1b +#define DUK_ASC_FS 0x1c +#define DUK_ASC_GS 0x1d +#define DUK_ASC_RS 0x1e +#define DUK_ASC_US 0x1f +#define DUK_ASC_SPACE 0x20 +#define DUK_ASC_EXCLAMATION 0x21 +#define DUK_ASC_DOUBLEQUOTE 0x22 +#define DUK_ASC_HASH 0x23 +#define DUK_ASC_DOLLAR 0x24 +#define DUK_ASC_PERCENT 0x25 +#define DUK_ASC_AMP 0x26 +#define DUK_ASC_SINGLEQUOTE 0x27 +#define DUK_ASC_LPAREN 0x28 +#define DUK_ASC_RPAREN 0x29 +#define DUK_ASC_STAR 0x2a +#define DUK_ASC_PLUS 0x2b +#define DUK_ASC_COMMA 0x2c +#define DUK_ASC_MINUS 0x2d +#define DUK_ASC_PERIOD 0x2e +#define DUK_ASC_SLASH 0x2f +#define DUK_ASC_0 0x30 +#define DUK_ASC_1 0x31 +#define DUK_ASC_2 0x32 +#define DUK_ASC_3 0x33 +#define DUK_ASC_4 0x34 +#define DUK_ASC_5 0x35 +#define DUK_ASC_6 0x36 +#define DUK_ASC_7 0x37 +#define DUK_ASC_8 0x38 +#define DUK_ASC_9 0x39 +#define DUK_ASC_COLON 0x3a +#define DUK_ASC_SEMICOLON 0x3b +#define DUK_ASC_LANGLE 0x3c +#define DUK_ASC_EQUALS 0x3d +#define DUK_ASC_RANGLE 0x3e +#define DUK_ASC_QUESTION 0x3f +#define DUK_ASC_ATSIGN 0x40 +#define DUK_ASC_UC_A 0x41 +#define DUK_ASC_UC_B 0x42 +#define DUK_ASC_UC_C 0x43 +#define DUK_ASC_UC_D 0x44 +#define DUK_ASC_UC_E 0x45 +#define DUK_ASC_UC_F 0x46 +#define DUK_ASC_UC_G 0x47 +#define DUK_ASC_UC_H 0x48 +#define DUK_ASC_UC_I 0x49 +#define DUK_ASC_UC_J 0x4a +#define DUK_ASC_UC_K 0x4b +#define DUK_ASC_UC_L 0x4c +#define DUK_ASC_UC_M 0x4d +#define DUK_ASC_UC_N 0x4e +#define DUK_ASC_UC_O 0x4f +#define DUK_ASC_UC_P 0x50 +#define DUK_ASC_UC_Q 0x51 +#define DUK_ASC_UC_R 0x52 +#define DUK_ASC_UC_S 0x53 +#define DUK_ASC_UC_T 0x54 +#define DUK_ASC_UC_U 0x55 +#define DUK_ASC_UC_V 0x56 +#define DUK_ASC_UC_W 0x57 +#define DUK_ASC_UC_X 0x58 +#define DUK_ASC_UC_Y 0x59 +#define DUK_ASC_UC_Z 0x5a +#define DUK_ASC_LBRACKET 0x5b +#define DUK_ASC_BACKSLASH 0x5c +#define DUK_ASC_RBRACKET 0x5d +#define DUK_ASC_CARET 0x5e +#define DUK_ASC_UNDERSCORE 0x5f +#define DUK_ASC_GRAVE 0x60 +#define DUK_ASC_LC_A 0x61 +#define DUK_ASC_LC_B 0x62 +#define DUK_ASC_LC_C 0x63 +#define DUK_ASC_LC_D 0x64 +#define DUK_ASC_LC_E 0x65 +#define DUK_ASC_LC_F 0x66 +#define DUK_ASC_LC_G 0x67 +#define DUK_ASC_LC_H 0x68 +#define DUK_ASC_LC_I 0x69 +#define DUK_ASC_LC_J 0x6a +#define DUK_ASC_LC_K 0x6b +#define DUK_ASC_LC_L 0x6c +#define DUK_ASC_LC_M 0x6d +#define DUK_ASC_LC_N 0x6e +#define DUK_ASC_LC_O 0x6f +#define DUK_ASC_LC_P 0x70 +#define DUK_ASC_LC_Q 0x71 +#define DUK_ASC_LC_R 0x72 +#define DUK_ASC_LC_S 0x73 +#define DUK_ASC_LC_T 0x74 +#define DUK_ASC_LC_U 0x75 +#define DUK_ASC_LC_V 0x76 +#define DUK_ASC_LC_W 0x77 +#define DUK_ASC_LC_X 0x78 +#define DUK_ASC_LC_Y 0x79 +#define DUK_ASC_LC_Z 0x7a +#define DUK_ASC_LCURLY 0x7b +#define DUK_ASC_PIPE 0x7c +#define DUK_ASC_RCURLY 0x7d +#define DUK_ASC_TILDE 0x7e +#define DUK_ASC_DEL 0x7f + +/* + * Unicode tables + */ + +#ifdef DUK_USE_SOURCE_NONBMP +/* + * Automatically generated by extract_chars.py, do not edit! + */ + +extern const duk_uint8_t duk_unicode_ids_noa[791]; +#else +/* + * Automatically generated by extract_chars.py, do not edit! + */ + +extern const duk_uint8_t duk_unicode_ids_noabmp[611]; +#endif + +#ifdef DUK_USE_SOURCE_NONBMP +/* + * Automatically generated by extract_chars.py, do not edit! + */ + +extern const duk_uint8_t duk_unicode_ids_m_let_noa[42]; +#else +/* + * Automatically generated by extract_chars.py, do not edit! + */ + +extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24]; +#endif + +#ifdef DUK_USE_SOURCE_NONBMP +/* + * Automatically generated by extract_chars.py, do not edit! + */ + +extern const duk_uint8_t duk_unicode_idp_m_ids_noa[397]; +#else +/* + * Automatically generated by extract_chars.py, do not edit! + */ + +extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348]; +#endif + +/* + * Automatically generated by extract_caseconv.py, do not edit! + */ + +extern const duk_uint8_t duk_unicode_caseconv_uc[1288]; +extern const duk_uint8_t duk_unicode_caseconv_lc[616]; + +#if defined(DUK_USE_REGEXP_CANON_WORKAROUND) +/* + * Automatically generated by extract_caseconv.py, do not edit! + */ + +extern const duk_uint16_t duk_unicode_re_canon_lookup[65536]; +#endif + +/* + * Extern + */ + +/* duk_unicode_support.c */ +#if !defined(DUK_SINGLE_FILE) +DUK_INTERNAL_DECL const duk_uint8_t duk_unicode_xutf8_markers[7]; +DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_digit[2]; +DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_white[22]; +DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_wordchar[8]; +DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_digit[4]; +DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_white[24]; +DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10]; +DUK_INTERNAL_DECL const duk_int8_t duk_is_idchar_tab[128]; +#endif /* !DUK_SINGLE_FILE */ + +/* + * Prototypes + */ + +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp); +#if defined(DUK_USE_ASSERTIONS) +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp); +#endif +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out); +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out); +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp); +DUK_INTERNAL_DECL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end); +DUK_INTERNAL_DECL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen); +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp); +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp); +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp); +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp); +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp); +DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase); +DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp); +DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp); + +#endif /* DUK_UNICODE_H_INCLUDED */ +/* + * Defines for JSON, especially duk_bi_json.c. + */ + +#ifndef DUK_JSON_H_INCLUDED +#define DUK_JSON_H_INCLUDED + +/* Encoding/decoding flags */ +#define DUK_JSON_FLAG_ASCII_ONLY (1 << 0) /* escape any non-ASCII characters */ +#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1 << 1) /* avoid key quotes when key is an ASCII Identifier */ +#define DUK_JSON_FLAG_EXT_CUSTOM (1 << 2) /* extended types: custom encoding */ +#define DUK_JSON_FLAG_EXT_COMPATIBLE (1 << 3) /* extended types: compatible encoding */ + +/* How much stack to require on entry to object/array encode */ +#define DUK_JSON_ENC_REQSTACK 32 + +/* How much stack to require on entry to object/array decode */ +#define DUK_JSON_DEC_REQSTACK 32 + +/* How large a loop detection stack to use */ +#define DUK_JSON_ENC_LOOPARRAY 64 + +/* Encoding state. Heap object references are all borrowed. */ +typedef struct { + duk_hthread *thr; + duk_bufwriter_ctx bw; /* output bufwriter */ + duk_hobject *h_replacer; /* replacer function */ + duk_hstring *h_gap; /* gap (if empty string, NULL) */ + duk_idx_t idx_proplist; /* explicit PropertyList */ + duk_idx_t idx_loop; /* valstack index of loop detection object */ + duk_small_uint_t flags; + duk_small_uint_t flag_ascii_only; + duk_small_uint_t flag_avoid_key_quotes; +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + duk_small_uint_t flag_ext_custom; + duk_small_uint_t flag_ext_compatible; + duk_small_uint_t flag_ext_custom_or_compatible; +#endif + duk_int_t recursion_depth; + duk_int_t recursion_limit; + duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */ +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + duk_small_uint_t stridx_custom_undefined; + duk_small_uint_t stridx_custom_nan; + duk_small_uint_t stridx_custom_neginf; + duk_small_uint_t stridx_custom_posinf; + duk_small_uint_t stridx_custom_function; +#endif + duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */ +} duk_json_enc_ctx; + +typedef struct { + duk_hthread *thr; + const duk_uint8_t *p; + const duk_uint8_t *p_start; + const duk_uint8_t *p_end; + duk_idx_t idx_reviver; + duk_small_uint_t flags; +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + duk_small_uint_t flag_ext_custom; + duk_small_uint_t flag_ext_compatible; + duk_small_uint_t flag_ext_custom_or_compatible; +#endif + duk_int_t recursion_depth; + duk_int_t recursion_limit; +} duk_json_dec_ctx; + +#endif /* DUK_JSON_H_INCLUDED */ +/* + * Ecmascript execution, support primitives. + */ + +#ifndef DUK_JS_H_INCLUDED +#define DUK_JS_H_INCLUDED + +/* Flags for call handling. */ +#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */ +#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */ +#define DUK_CALL_FLAG_IS_RESUME (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */ +#define DUK_CALL_FLAG_IS_TAILCALL (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */ +#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 4) /* call is a direct eval call */ + +/* Flags for duk_js_equals_helper(). */ +#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */ +#define DUK_EQUALS_FLAG_STRICT (1 << 1) /* use strict equality instead of non-strict equality */ + +/* Flags for duk_js_compare_helper(). */ +#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 0) /* eval left argument first */ +#define DUK_COMPARE_FLAG_NEGATE (1 << 1) /* negate result */ + +/* conversions, coercions, comparison, etc */ +DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv); +DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x); +DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx); +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h); +DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags); +DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2); +DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2); +#if 0 /* unused */ +DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2); +#endif +DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags); +DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); +DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); +DUK_INTERNAL_DECL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x); + +#define duk_js_equals(thr,tv_x,tv_y) \ + duk_js_equals_helper((thr), (tv_x), (tv_y), 0) +#define duk_js_strict_equals(tv_x,tv_y) \ + duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT) +#define duk_js_samevalue(tv_x,tv_y) \ + duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE) + +/* E5 Sections 11.8.1, 11.8.5; x < y */ +#define duk_js_lessthan(thr,tv_x,tv_y) \ + duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) + +/* E5 Sections 11.8.2, 11.8.5; x > y --> y < x */ +#define duk_js_greaterthan(thr,tv_x,tv_y) \ + duk_js_compare_helper((thr), (tv_y), (tv_x), 0) + +/* E5 Sections 11.8.3, 11.8.5; x <= y --> not (x > y) --> not (y < x) */ +#define duk_js_lessthanorequal(thr,tv_x,tv_y) \ + duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE) + +/* E5 Sections 11.8.4, 11.8.5; x >= y --> not (x < y) */ +#define duk_js_greaterthanorequal(thr,tv_x,tv_y) \ + duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE) + +/* identifiers and environment handling */ +#if 0 /*unused*/ +DUK_INTERNAL duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name); +#endif +DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag); +DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag); +DUK_INTERNAL_DECL void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict); +DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict); +#if 0 /*unused*/ +DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name); +#endif +DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name); +DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl); +DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act); +DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase); +DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom); +DUK_INTERNAL_DECL +void duk_js_push_closure(duk_hthread *thr, + duk_hcompiledfunction *fun_temp, + duk_hobject *outer_var_env, + duk_hobject *outer_lex_env, + duk_bool_t add_auto_proto); + +/* call handling */ +DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags); +DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags); +DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, duk_idx_t num_stack_args, duk_idx_t num_stack_res); +DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags); + +/* bytecode execution */ +DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr); + +#endif /* DUK_JS_H_INCLUDED */ +#ifndef DUK_NUMCONV_H_INCLUDED +#define DUK_NUMCONV_H_INCLUDED + +/* + * Number-to-string conversion. The semantics of these is very tightly + * bound with the Ecmascript semantics required for call sites. + */ + +/* Output a specified number of digits instead of using the shortest + * form. Used for toPrecision() and toFixed(). + */ +#define DUK_N2S_FLAG_FIXED_FORMAT (1 << 0) + +/* Force exponential format. Used for toExponential(). */ +#define DUK_N2S_FLAG_FORCE_EXP (1 << 1) + +/* If number would need zero padding (for whole number part), use + * exponential format instead. E.g. if input number is 12300, 3 + * digits are generated ("123"), output "1.23e+4" instead of "12300". + * Used for toPrecision(). + */ +#define DUK_N2S_FLAG_NO_ZERO_PAD (1 << 2) + +/* Digit count indicates number of fractions (i.e. an absolute + * digit index instead of a relative one). Used together with + * DUK_N2S_FLAG_FIXED_FORMAT for toFixed(). + */ +#define DUK_N2S_FLAG_FRACTION_DIGITS (1 << 3) + +/* + * String-to-number conversion + */ + +/* Maximum exponent value when parsing numbers. This is not strictly + * compliant as there should be no upper limit, but as we parse the + * exponent without a bigint, impose some limit. + */ +#define DUK_S2N_MAX_EXPONENT 1000000000 + +/* Trim white space (= allow leading and trailing whitespace) */ +#define DUK_S2N_FLAG_TRIM_WHITE (1 << 0) + +/* Allow exponent */ +#define DUK_S2N_FLAG_ALLOW_EXP (1 << 1) + +/* Allow trailing garbage (e.g. treat "123foo" as "123) */ +#define DUK_S2N_FLAG_ALLOW_GARBAGE (1 << 2) + +/* Allow leading plus sign */ +#define DUK_S2N_FLAG_ALLOW_PLUS (1 << 3) + +/* Allow leading minus sign */ +#define DUK_S2N_FLAG_ALLOW_MINUS (1 << 4) + +/* Allow 'Infinity' */ +#define DUK_S2N_FLAG_ALLOW_INF (1 << 5) + +/* Allow fraction part */ +#define DUK_S2N_FLAG_ALLOW_FRAC (1 << 6) + +/* Allow naked fraction (e.g. ".123") */ +#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1 << 7) + +/* Allow empty fraction (e.g. "123.") */ +#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1 << 8) + +/* Allow empty string to be interpreted as 0 */ +#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1 << 9) + +/* Allow leading zeroes (e.g. "0123" -> "123") */ +#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1 << 10) + +/* Allow automatic detection of hex base ("0x" or "0X" prefix), + * overrides radix argument and forces integer mode. + */ +#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1 << 11) + +/* Allow automatic detection of octal base, overrides radix + * argument and forces integer mode. + */ +#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 12) + +/* + * Prototypes + */ + +DUK_INTERNAL_DECL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags); +DUK_INTERNAL_DECL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags); + +#endif /* DUK_NUMCONV_H_INCLUDED */ +/* + * Prototypes for built-in functions not automatically covered by the + * header declarations emitted by genbuiltins.py. + */ + +#ifndef DUK_BUILTIN_PROTOS_H_INCLUDED +#define DUK_BUILTIN_PROTOS_H_INCLUDED + +/* Buffer size needed for duk_bi_date_format_timeval(). + * Accurate value is 32 + 1 for NUL termination: + * >>> len('+123456-01-23T12:34:56.123+12:34') + * 32 + * Include additional space to be safe. + */ +#define DUK_BI_DATE_ISO8601_BUFSIZE 48 + +/* Maximum length of CommonJS module identifier to resolve. Length includes + * both current module ID, requested (possibly relative) module ID, and a + * slash in between. + */ +#define DUK_BI_COMMONJS_MODULE_ID_LIMIT 256 + +/* Helpers exposed for internal use */ +DUK_INTERNAL_DECL 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_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags); +DUK_INTERNAL_DECL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf); +DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year); +DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year); +DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x); +/* Built-in providers */ +#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) +DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx); +#endif +#if defined(DUK_USE_DATE_NOW_TIME) +DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx); +#endif +#if defined(DUK_USE_DATE_NOW_WINDOWS) +DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx); +#endif +#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) +DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d); +#endif +#if defined(DUK_USE_DATE_TZO_WINDOWS) +DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d); +#endif +#if defined(DUK_USE_DATE_PRS_STRPTIME) +DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str); +#endif +#if defined(DUK_USE_DATE_PRS_GETDATE) +DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str); +#endif +#if defined(DUK_USE_DATE_FMT_STRFTIME) +DUK_INTERNAL_DECL 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); +#endif + +DUK_INTERNAL_DECL +void duk_bi_json_parse_helper(duk_context *ctx, + duk_idx_t idx_value, + duk_idx_t idx_reviver, + duk_small_uint_t flags); +DUK_INTERNAL_DECL +void duk_bi_json_stringify_helper(duk_context *ctx, + duk_idx_t idx_value, + duk_idx_t idx_replacer, + duk_idx_t idx_space, + duk_small_uint_t flags); + +#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */ +/* + * Selftest code + */ + +#ifndef DUK_SELFTEST_H_INCLUDED +#define DUK_SELFTEST_H_INCLUDED + +#if defined(DUK_USE_SELF_TESTS) +DUK_INTERNAL_DECL void duk_selftest_run_tests(void); +#endif + +#endif /* DUK_SELFTEST_H_INCLUDED */ + +#endif /* DUK_INTERNAL_H_INCLUDED */ +/* + * Replacements for missing platform functions. + * + * Unlike the originals, fpclassify() and signbit() replacements don't + * work on any floating point types, only doubles. The C typing here + * mimics the standard prototypes. + */ + +/* include removed: duk_internal.h */ + +#if defined(DUK_USE_COMPUTED_NAN) +DUK_INTERNAL double duk_computed_nan; +#endif + +#if defined(DUK_USE_COMPUTED_INFINITY) +DUK_INTERNAL double duk_computed_infinity; +#endif + +#if defined(DUK_USE_REPL_FPCLASSIFY) +DUK_INTERNAL int duk_repl_fpclassify(double x) { + duk_double_union u; + duk_uint_fast16_t expt; + duk_small_int_t mzero; + + u.d = x; + expt = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL); + if (expt > 0x0000UL && expt < 0x7ff0UL) { + /* expt values [0x001,0x7fe] = normal */ + return DUK_FP_NORMAL; + } + + mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0); + if (expt == 0x0000UL) { + /* expt 0x000 is zero/subnormal */ + if (mzero) { + return DUK_FP_ZERO; + } else { + return DUK_FP_SUBNORMAL; + } + } else { + /* expt 0xfff is infinite/nan */ + if (mzero) { + return DUK_FP_INFINITE; + } else { + return DUK_FP_NAN; + } + } +} +#endif + +#if defined(DUK_USE_REPL_SIGNBIT) +DUK_INTERNAL int duk_repl_signbit(double x) { + duk_double_union u; + u.d = x; + return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL); +} +#endif + +#if defined(DUK_USE_REPL_ISFINITE) +DUK_INTERNAL int duk_repl_isfinite(double x) { + int c = DUK_FPCLASSIFY(x); + if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { + return 0; + } else { + return 1; + } +} +#endif + +#if defined(DUK_USE_REPL_ISNAN) +DUK_INTERNAL int duk_repl_isnan(double x) { + int c = DUK_FPCLASSIFY(x); + return (c == DUK_FP_NAN); +} +#endif + +#if defined(DUK_USE_REPL_ISINF) +DUK_INTERNAL int duk_repl_isinf(double x) { + int c = DUK_FPCLASSIFY(x); + return (c == DUK_FP_INFINITE); +} +#endif +/* + * Shared error message strings + * + * To minimize code footprint, try to share error messages inside Duktape + * code. Modern compilers will do this automatically anyway, this is mostly + * for older compilers. + */ + +/* include removed: duk_internal.h */ + +/* Mostly API and built-in method related */ +DUK_INTERNAL const char *duk_str_internal_error = "internal error"; +DUK_INTERNAL const char *duk_str_invalid_count = "invalid count"; +DUK_INTERNAL const char *duk_str_invalid_call_args = "invalid call args"; +DUK_INTERNAL const char *duk_str_not_constructable = "not constructable"; +DUK_INTERNAL const char *duk_str_not_callable = "not callable"; +DUK_INTERNAL const char *duk_str_not_extensible = "not extensible"; +DUK_INTERNAL const char *duk_str_not_writable = "not writable"; +DUK_INTERNAL const char *duk_str_not_configurable = "not configurable"; + +DUK_INTERNAL const char *duk_str_invalid_context = "invalid context"; +DUK_INTERNAL const char *duk_str_push_beyond_alloc_stack = "attempt to push beyond currently allocated stack"; +DUK_INTERNAL const char *duk_str_not_buffer = "not buffer"; /* still in use with verbose messages */ +DUK_INTERNAL const char *duk_str_unexpected_type = "unexpected type"; +DUK_INTERNAL const char *duk_str_defaultvalue_coerce_failed = "[[DefaultValue]] coerce failed"; +DUK_INTERNAL const char *duk_str_number_outside_range = "number outside range"; +DUK_INTERNAL const char *duk_str_not_object_coercible = "not object coercible"; +DUK_INTERNAL const char *duk_str_string_too_long = "string too long"; +DUK_INTERNAL const char *duk_str_buffer_too_long = "buffer too long"; +DUK_INTERNAL const char *duk_str_sprintf_too_long = "sprintf message too long"; +DUK_INTERNAL const char *duk_str_alloc_failed = "alloc failed"; +DUK_INTERNAL const char *duk_str_pop_too_many = "attempt to pop too many entries"; +DUK_INTERNAL const char *duk_str_wrong_buffer_type = "wrong buffer type"; +DUK_INTERNAL const char *duk_str_encode_failed = "encode failed"; +DUK_INTERNAL const char *duk_str_decode_failed = "decode failed"; +DUK_INTERNAL const char *duk_str_no_sourcecode = "no sourcecode"; +DUK_INTERNAL const char *duk_str_concat_result_too_long = "concat result too long"; +DUK_INTERNAL const char *duk_str_unimplemented = "unimplemented"; +DUK_INTERNAL const char *duk_str_unsupported = "unsupported"; +DUK_INTERNAL const char *duk_str_array_length_over_2g = "array length over 2G"; + +/* JSON */ +DUK_INTERNAL const char *duk_str_fmt_ptr = "%p"; +DUK_INTERNAL const char *duk_str_fmt_invalid_json = "invalid json (at offset %ld)"; +DUK_INTERNAL const char *duk_str_jsondec_reclimit = "json decode recursion limit"; +DUK_INTERNAL const char *duk_str_jsonenc_reclimit = "json encode recursion limit"; +DUK_INTERNAL const char *duk_str_cyclic_input = "cyclic input"; + +/* Object property access */ +DUK_INTERNAL const char *duk_str_proxy_revoked = "proxy revoked"; +DUK_INTERNAL const char *duk_str_invalid_base = "invalid base value"; +DUK_INTERNAL const char *duk_str_strict_caller_read = "attempt to read strict 'caller'"; +DUK_INTERNAL const char *duk_str_proxy_rejected = "proxy rejected"; +DUK_INTERNAL const char *duk_str_invalid_array_length = "invalid array length"; +DUK_INTERNAL const char *duk_str_array_length_write_failed = "array length write failed"; +DUK_INTERNAL const char *duk_str_array_length_not_writable = "array length non-writable"; +DUK_INTERNAL const char *duk_str_setter_undefined = "setter undefined"; +DUK_INTERNAL const char *duk_str_redefine_virt_prop = "attempt to redefine virtual property"; +DUK_INTERNAL const char *duk_str_invalid_descriptor = "invalid descriptor"; +DUK_INTERNAL const char *duk_str_property_is_virtual = "property is virtual"; + +/* Compiler */ +DUK_INTERNAL const char *duk_str_parse_error = "parse error"; +DUK_INTERNAL const char *duk_str_duplicate_label = "duplicate label"; +DUK_INTERNAL const char *duk_str_invalid_label = "invalid label"; +DUK_INTERNAL const char *duk_str_invalid_array_literal = "invalid array literal"; +DUK_INTERNAL const char *duk_str_invalid_object_literal = "invalid object literal"; +DUK_INTERNAL const char *duk_str_invalid_var_declaration = "invalid variable declaration"; +DUK_INTERNAL const char *duk_str_cannot_delete_identifier = "cannot delete identifier"; +DUK_INTERNAL const char *duk_str_invalid_expression = "invalid expression"; +DUK_INTERNAL const char *duk_str_invalid_lvalue = "invalid lvalue"; +DUK_INTERNAL const char *duk_str_expected_identifier = "expected identifier"; +DUK_INTERNAL const char *duk_str_empty_expr_not_allowed = "empty expression not allowed"; +DUK_INTERNAL const char *duk_str_invalid_for = "invalid for statement"; +DUK_INTERNAL const char *duk_str_invalid_switch = "invalid switch statement"; +DUK_INTERNAL const char *duk_str_invalid_break_cont_label = "invalid break/continue label"; +DUK_INTERNAL const char *duk_str_invalid_return = "invalid return"; +DUK_INTERNAL const char *duk_str_invalid_try = "invalid try"; +DUK_INTERNAL const char *duk_str_invalid_throw = "invalid throw"; +DUK_INTERNAL const char *duk_str_with_in_strict_mode = "with in strict mode"; +DUK_INTERNAL const char *duk_str_func_stmt_not_allowed = "function statement not allowed"; +DUK_INTERNAL const char *duk_str_unterminated_stmt = "unterminated statement"; +DUK_INTERNAL const char *duk_str_invalid_arg_name = "invalid argument name"; +DUK_INTERNAL const char *duk_str_invalid_func_name = "invalid function name"; +DUK_INTERNAL const char *duk_str_invalid_getset_name = "invalid getter/setter name"; +DUK_INTERNAL const char *duk_str_func_name_required = "function name required"; + +/* Regexp */ +DUK_INTERNAL const char *duk_str_invalid_quantifier_no_atom = "quantifier without preceding atom"; +DUK_INTERNAL const char *duk_str_invalid_quantifier_values = "quantifier values invalid (qmin > qmax)"; +DUK_INTERNAL const char *duk_str_quantifier_too_many_copies = "quantifier expansion requires too many atom copies"; +DUK_INTERNAL const char *duk_str_unexpected_closing_paren = "unexpected closing parenthesis"; +DUK_INTERNAL const char *duk_str_unexpected_end_of_pattern = "unexpected end of pattern"; +DUK_INTERNAL const char *duk_str_unexpected_regexp_token = "unexpected token in regexp"; +DUK_INTERNAL const char *duk_str_invalid_regexp_flags = "invalid regexp flags"; +DUK_INTERNAL const char *duk_str_invalid_backrefs = "invalid backreference(s)"; + +/* Limits */ +DUK_INTERNAL const char *duk_str_valstack_limit = "valstack limit"; +DUK_INTERNAL const char *duk_str_callstack_limit = "callstack limit"; +DUK_INTERNAL const char *duk_str_catchstack_limit = "catchstack limit"; +DUK_INTERNAL const char *duk_str_prototype_chain_limit = "prototype chain limit"; +DUK_INTERNAL const char *duk_str_bound_chain_limit = "function call bound chain limit"; +DUK_INTERNAL const char *duk_str_c_callstack_limit = "C call stack depth limit"; +DUK_INTERNAL const char *duk_str_compiler_recursion_limit = "compiler recursion limit"; +DUK_INTERNAL const char *duk_str_bytecode_limit = "bytecode limit"; +DUK_INTERNAL const char *duk_str_reg_limit = "register limit"; +DUK_INTERNAL const char *duk_str_temp_limit = "temp limit"; +DUK_INTERNAL const char *duk_str_const_limit = "const limit"; +DUK_INTERNAL const char *duk_str_func_limit = "function limit"; +DUK_INTERNAL const char *duk_str_regexp_compiler_recursion_limit = "regexp compiler recursion limit"; +DUK_INTERNAL const char *duk_str_regexp_executor_recursion_limit = "regexp executor recursion limit"; +DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit"; + +/* Misc */ +/* + * Debugging macro calls. + */ + +/* include removed: duk_internal.h */ + +#ifdef DUK_USE_DEBUG + +/* + * Debugging enabled + */ + +#include +#include +#include + +#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE +DUK_LOCAL char duk__debug_buf[DUK__DEBUG_BUFSIZE]; + +DUK_LOCAL const char *duk__get_level_string(duk_small_int_t level) { + switch ((int) level) { + case DUK_LEVEL_DEBUG: + return "D"; + case DUK_LEVEL_DDEBUG: + return "DD"; + case DUK_LEVEL_DDDEBUG: + return "DDD"; + } + return "???"; +} + +#ifdef DUK_USE_DPRINT_COLORS + +/* http://en.wikipedia.org/wiki/ANSI_escape_code */ +#define DUK__TERM_REVERSE "\x1b[7m" +#define DUK__TERM_BRIGHT "\x1b[1m" +#define DUK__TERM_RESET "\x1b[0m" +#define DUK__TERM_BLUE "\x1b[34m" +#define DUK__TERM_RED "\x1b[31m" + +DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) { + DUK_UNREF(level); + return (const char *) DUK__TERM_RED; +} + +DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) { + switch ((int) level) { + case DUK_LEVEL_DEBUG: + return (const char *) (DUK__TERM_RESET DUK__TERM_BRIGHT); + case DUK_LEVEL_DDEBUG: + return (const char *) (DUK__TERM_RESET); + case DUK_LEVEL_DDDEBUG: + return (const char *) (DUK__TERM_RESET DUK__TERM_BLUE); + } + return (const char *) DUK__TERM_RESET; +} + +DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) { + DUK_UNREF(level); + return (const char *) DUK__TERM_RESET; +} + +#else + +DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) { + DUK_UNREF(level); + return (const char *) ""; +} + +DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) { + DUK_UNREF(level); + return (const char *) ""; +} + +DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) { + DUK_UNREF(level); + return (const char *) ""; +} + +#endif /* DUK_USE_DPRINT_COLORS */ + +#ifdef DUK_USE_VARIADIC_MACROS + +DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + + DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE); + duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); + + DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%ld (%s):%s %s%s\n", + (const char *) duk__get_term_1(level), + (const char *) duk__get_level_string(level), + (const char *) file, + (long) line, + (const char *) func, + (const char *) duk__get_term_2(level), + (const char *) duk__debug_buf, + (const char *) duk__get_term_3(level)); + DUK_FFLUSH(DUK_STDERR); + + va_end(ap); +} + +#else /* DUK_USE_VARIADIC_MACROS */ + +DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE]; +DUK_INTERNAL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE]; +DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE]; +DUK_INTERNAL duk_small_int_t duk_debug_level_stash; + +DUK_INTERNAL void duk_debug_log(const char *fmt, ...) { + va_list ap; + duk_small_int_t level = duk_debug_level_stash; + + va_start(ap, fmt); + + DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE); + duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); + + DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%s (%s):%s %s%s\n", + (const char *) duk__get_term_1(level), + (const char *) duk__get_level_string(duk_debug_level_stash), + (const char *) duk_debug_file_stash, + (const char *) duk_debug_line_stash, + (const char *) duk_debug_func_stash, + (const char *) duk__get_term_2(level), + (const char *) duk__debug_buf, + (const char *) duk__get_term_3(level)); + DUK_FFLUSH(DUK_STDERR); + + va_end(ap); +} + +#endif /* DUK_USE_VARIADIC_MACROS */ + +#else /* DUK_USE_DEBUG */ + +/* + * Debugging disabled + */ + +#endif /* DUK_USE_DEBUG */ +/* + * Automatically generated by genbuiltins.py, do not edit! + */ + +/* include removed: duk_internal.h */ + +#if defined(DUK_USE_ROM_STRINGS) +#error ROM support not enabled, rerun make_dist.py with --rom-support +#else /* DUK_USE_ROM_STRINGS */ +DUK_INTERNAL const duk_uint8_t duk_strings_data[1049] = { +79,104,209,144,168,105,6,78,182,139,90,122,8,154,140,35,103,35,117,193,73, +5,52,116,180,104,166,135,52,189,4,98,12,27,178,156,80,211,31,161,115,150, +64,52,221,109,24,18,68,157,24,38,67,118,36,55,73,119,151,164,140,93,18,117, +128,153,201,228,201,205,2,250,8,196,24,232,104,82,146,40,232,193,48,118, +168,37,147,212,54,127,113,208,70,32,194,187,68,54,127,113,208,70,32,196, +123,68,54,127,113,209,44,12,121,7,208,70,32,194,186,134,207,236,126,219, +160,140,65,133,246,136,108,254,199,237,186,8,196,24,87,80,217,253,159,217, +116,17,136,48,190,209,13,159,217,253,151,65,24,131,12,233,86,224,79,236, +254,203,160,140,65,134,116,171,112,39,246,223,105,208,70,32,193,140,183,4, +11,55,92,20,244,141,169,186,50,11,164,109,77,208,208,165,36,79,215,185,13, +153,34,110,204,241,32,6,66,84,11,112,200,84,52,157,124,92,242,70,120,45,64, +186,17,22,138,38,0,172,140,19,154,84,26,145,0,86,69,17,180,97,34,0,172,132, +75,144,215,77,221,91,132,5,147,178,156,80,211,30,160,93,9,215,21,115,119, +169,49,75,211,138,26,101,205,222,68,157,47,78,40,105,151,55,120,204,156, +189,56,161,166,52,157,72,136,138,65,154,232,147,162,4,136,150,81,115,66, +208,210,37,96,148,250,134,140,151,39,212,125,255,221,125,73,80,209,146,233, +124,93,55,79,15,34,196,230,202,113,160,166,232,157,132,148,128,98,28,46, +114,200,6,153,180,96,73,19,74,113,67,76,103,5,36,20,211,70,140,133,67,72, +49,245,160,235,81,212,52,168,106,39,132,253,111,80,210,161,168,158,5,245, +191,96,31,172,15,208,23,226,190,131,232,62,131,232,11,251,127,93,245,223, +93,251,172,234,27,80,45,3,250,14,140,19,34,65,19,81,132,108,228,97,1,107, +33,12,32,45,100,136,206,9,12,196,155,134,69,146,100,235,226,231,146,51,194, +72,218,48,145,4,200,119,89,189,81,49,39,72,147,235,226,233,186,120,121,58, +226,167,90,124,93,55,107,71,137,33,68,68,130,64,206,75,189,209,156,144,84, +44,141,3,8,137,187,178,156,80,211,26,110,242,100,230,146,120,121,8,48,76,6, +89,26,105,157,65,196,201,213,145,166,153,212,28,76,157,113,75,34,78,62,14, +38,73,105,228,142,136,178,48,141,152,228,73,150,83,0,148,39,137,75,67,73, +214,209,129,36,85,190,206,32,17,6,9,128,141,3,8,130,161,100,235,64,194,24, +52,41,73,19,189,200,108,201,19,111,181,2,232,66,239,173,37,230,157,244,56, +153,4,225,145,27,233,93,22,1,114,62,251,80,69,128,121,247,213,146,228,109, +79,190,212,17,35,106,125,246,78,164,68,68,111,175,23,217,45,13,33,119,208, +68,210,38,250,192,61,91,233,80,208,45,25,36,81,190,156,13,26,201,19,239, +162,2,214,66,31,125,153,226,64,13,27,236,72,96,130,68,62,251,48,68,196,153, +119,217,157,18,56,156,199,161,100,42,26,250,77,36,140,122,40,144,19,34,9, +24,246,103,139,172,150,56,125,145,1,17,29,44,112,250,183,0,100,24,200,218, +140,228,185,130,9,19,237,190,208,73,184,146,35,68,146,163,8,50,178,99,136, +44,89,196,2,33,70,64,208,196,67,74,226,88,17,105,73,24,186,37,40,38,5,133, +161,89,4,183,25,115,119,86,227,118,83,138,26,103,255,223,209,106,141,25,11, +244,95,117,56,208,159,250,223,251,250,45,52,13,250,47,186,156,104,79,253, +111,253,253,22,144,210,253,23,221,78,52,39,254,187,254,254,139,77,67,75, +244,95,117,56,208,159,250,239,251,250,45,22,141,23,209,125,212,227,66,127, +235,63,239,69,163,69,247,83,141,9,255,165,12,72,5,16,64,145,10,32,76,71,64, +156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44,147,32,134,226, +17,114,33,202,134,129,107,192,202,232,160,180,104,166,135,52,72,40,144,213, +33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34,98,57,38,116,72, +179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153,42,228,12,182, +58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114,94,100,104, +228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80,46,68,82,24, +245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6,33,223,20, +84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112,130,44,96, +}; +#endif /* DUK_USE_ROM_STRINGS */ + +#if defined(DUK_USE_ROM_OBJECTS) +#error ROM support not enabled, rerun make_dist.py with --rom-support +#else /* DUK_USE_ROM_OBJECTS */ +/* native functions: 149 */ +DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { + duk_bi_array_constructor, + duk_bi_array_constructor_is_array, + duk_bi_array_prototype_concat, + duk_bi_array_prototype_indexof_shared, + duk_bi_array_prototype_iter_shared, + duk_bi_array_prototype_join_shared, + duk_bi_array_prototype_pop, + duk_bi_array_prototype_push, + duk_bi_array_prototype_reduce_shared, + duk_bi_array_prototype_reverse, + duk_bi_array_prototype_shift, + duk_bi_array_prototype_slice, + duk_bi_array_prototype_sort, + duk_bi_array_prototype_splice, + duk_bi_array_prototype_to_string, + duk_bi_array_prototype_unshift, + duk_bi_arraybuffer_constructor, + duk_bi_arraybuffer_isview, + duk_bi_boolean_constructor, + duk_bi_boolean_prototype_tostring_shared, + duk_bi_buffer_compare_shared, + duk_bi_buffer_constructor, + duk_bi_buffer_prototype_tostring_shared, + duk_bi_buffer_readfield, + duk_bi_buffer_slice_shared, + duk_bi_buffer_writefield, + duk_bi_dataview_constructor, + duk_bi_date_constructor, + duk_bi_date_constructor_now, + duk_bi_date_constructor_parse, + duk_bi_date_constructor_utc, + duk_bi_date_prototype_get_shared, + duk_bi_date_prototype_get_timezone_offset, + duk_bi_date_prototype_set_shared, + duk_bi_date_prototype_set_time, + duk_bi_date_prototype_to_json, + duk_bi_date_prototype_tostring_shared, + duk_bi_date_prototype_value_of, + duk_bi_duktape_object_act, + duk_bi_duktape_object_compact, + duk_bi_duktape_object_dec, + duk_bi_duktape_object_enc, + duk_bi_duktape_object_fin, + duk_bi_duktape_object_gc, + duk_bi_duktape_object_info, + duk_bi_error_constructor_shared, + duk_bi_error_prototype_filename_getter, + duk_bi_error_prototype_filename_setter, + duk_bi_error_prototype_linenumber_getter, + duk_bi_error_prototype_linenumber_setter, + duk_bi_error_prototype_stack_getter, + duk_bi_error_prototype_stack_setter, + duk_bi_error_prototype_to_string, + duk_bi_function_constructor, + duk_bi_function_prototype, + duk_bi_function_prototype_apply, + duk_bi_function_prototype_bind, + duk_bi_function_prototype_call, + duk_bi_function_prototype_to_string, + duk_bi_global_object_decode_uri, + duk_bi_global_object_decode_uri_component, + duk_bi_global_object_encode_uri, + duk_bi_global_object_encode_uri_component, + duk_bi_global_object_escape, + duk_bi_global_object_eval, + duk_bi_global_object_is_finite, + duk_bi_global_object_is_nan, + duk_bi_global_object_parse_float, + duk_bi_global_object_parse_int, + duk_bi_global_object_print_helper, + duk_bi_global_object_require, + duk_bi_global_object_unescape, + duk_bi_json_object_parse, + duk_bi_json_object_stringify, + duk_bi_logger_constructor, + duk_bi_logger_prototype_fmt, + duk_bi_logger_prototype_log_shared, + duk_bi_logger_prototype_raw, + duk_bi_math_object_max, + duk_bi_math_object_min, + duk_bi_math_object_onearg_shared, + duk_bi_math_object_random, + duk_bi_math_object_twoarg_shared, + duk_bi_nodejs_buffer_byte_length, + duk_bi_nodejs_buffer_concat, + duk_bi_nodejs_buffer_constructor, + duk_bi_nodejs_buffer_copy, + duk_bi_nodejs_buffer_fill, + duk_bi_nodejs_buffer_is_buffer, + duk_bi_nodejs_buffer_is_encoding, + duk_bi_nodejs_buffer_tojson, + duk_bi_nodejs_buffer_tostring, + duk_bi_nodejs_buffer_write, + duk_bi_number_constructor, + duk_bi_number_prototype_to_exponential, + duk_bi_number_prototype_to_fixed, + duk_bi_number_prototype_to_locale_string, + duk_bi_number_prototype_to_precision, + duk_bi_number_prototype_to_string, + duk_bi_number_prototype_value_of, + duk_bi_object_constructor, + duk_bi_object_constructor_create, + duk_bi_object_constructor_define_properties, + duk_bi_object_constructor_define_property, + duk_bi_object_constructor_get_own_property_descriptor, + duk_bi_object_constructor_is_extensible, + duk_bi_object_constructor_is_sealed_frozen_shared, + duk_bi_object_constructor_keys_shared, + duk_bi_object_constructor_prevent_extensions, + duk_bi_object_constructor_seal_freeze_shared, + duk_bi_object_getprototype_shared, + duk_bi_object_prototype_has_own_property, + duk_bi_object_prototype_is_prototype_of, + duk_bi_object_prototype_property_is_enumerable, + duk_bi_object_prototype_to_locale_string, + duk_bi_object_prototype_to_string, + duk_bi_object_prototype_value_of, + duk_bi_object_setprototype_shared, + duk_bi_pointer_constructor, + duk_bi_pointer_prototype_tostring_shared, + duk_bi_proxy_constructor, + duk_bi_regexp_constructor, + duk_bi_regexp_prototype_exec, + duk_bi_regexp_prototype_test, + duk_bi_regexp_prototype_to_string, + duk_bi_string_constructor, + duk_bi_string_constructor_from_char_code, + duk_bi_string_prototype_caseconv_shared, + duk_bi_string_prototype_char_at, + duk_bi_string_prototype_char_code_at, + duk_bi_string_prototype_concat, + duk_bi_string_prototype_indexof_shared, + duk_bi_string_prototype_locale_compare, + duk_bi_string_prototype_match, + duk_bi_string_prototype_replace, + duk_bi_string_prototype_search, + duk_bi_string_prototype_slice, + duk_bi_string_prototype_split, + duk_bi_string_prototype_substr, + duk_bi_string_prototype_substring, + duk_bi_string_prototype_to_string, + duk_bi_string_prototype_trim, + duk_bi_thread_constructor, + duk_bi_thread_current, + duk_bi_thread_resume, + duk_bi_thread_yield, + duk_bi_type_error_thrower, + duk_bi_typedarray_constructor, + duk_bi_typedarray_set, +}; +#if defined(DUK_USE_BUILTIN_INITJS) +DUK_INTERNAL const duk_uint8_t duk_initjs_data[204] = { +40,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116, +105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101, +102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97, +108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117, +109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98, +108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99, +108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34, +41,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,79,98,106, +101,99,116,46,99,114,101,97,116,101,40,110,117,108,108,41,41,125,41,40,116, +104,105,115,44,68,117,107,116,97,112,101,41,59,10,0, +}; +#endif /* DUK_USE_BUILTIN_INITJS */ +#if defined(DUK_USE_DOUBLE_LE) +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = { +105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6, +152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2, +240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75, +14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99, +203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252, +176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86, +148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212, +243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105, +21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70, +145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192, +158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26, +228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14, +202,3,255,254,32,234,0,0,0,0,0,0,7,195,248,119,0,0,0,0,0,0,3,193,252,57, +136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153, +40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223, +200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231, +119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144, +138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12, +166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212, +19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18, +17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136, +100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151, +30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246, +240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46, +236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199, +135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163, +208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31, +240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221, +82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150, +158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157, +135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157, +217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203, +46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238, +230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93, +205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249, +230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16, +237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114, +223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113, +119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5, +195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130, +135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80, +128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175, +61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94, +123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65, +250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47, +102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8, +105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7, +183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66, +15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0, +195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129, +202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101, +131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52, +133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50, +195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28, +121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225, +179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253, +242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151, +148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196, +122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211, +150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138, +48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31, +255,255,255,255,255,253,239,240,153,178,103,95,173,6,101,88,176,0,64,0,0,0, +0,0,0,3,168,0,0,0,0,0,0,31,15,241,26,19,233,201,169,38,180,91,242,103,70, +147,58,77,75,48,0,0,0,0,0,0,60,31,226,51,162,199,131,82,77,104,183,228,206, +141,38,116,154,150,96,0,0,0,0,0,0,120,127,128,15,248,192,70,40,0,0,0,0,0,0, +0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248, +190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167, +126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64, +247,111,238,56,0,127,199,2,49,72,0,0,0,0,0,0,248,127,180,81,36,4,51,166, +248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105, +244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196, +195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77, +59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32, +80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156, +184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132, +0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126, +238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33, +196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244, +171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62, +94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122, +101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156, +43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121, +113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223, +187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61, +251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231, +151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154, +121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217, +167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100, +43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10, +231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205, +211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3, +208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19, +15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60, +189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43, +224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229, +233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195, +200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144, +24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0, +0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159, +240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230, +115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45, +252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185, +111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221, +143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206, +238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53, +60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85, +165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,105,87,20,139,10,191,5, +64,130,76,156,197,132,1,101,91,91,187,22,176,36,8,28,201,204,160,119,156, +253,127,33,23,115,31,193,102,79,142,202,44,15,232,34,182,84,113,95,115,248, +52,201,241,216,176,139,0,59,148,152,85,239,47,108,254,5,66,76,1,130,212,69, +79,178,16,148,8,61,58,52,170,49,190,202,6,105,219,251,52,245,7,49,252,22, +157,26,85,25,64,205,59,127,102,158,160,246,63,74,7,135,23,53,2,65,48,227, +223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195, +211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15, +47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0, +136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110, +88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0, +21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23, +134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0, +191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,0,0,0,0,65,226, +32,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144, +60,56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7, +147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3, +252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255, +167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67, +184,2,172,254,0,0,255,171,8,137,144,0,0,0,0,0,0,0,128,68,73,4,195,187,126, +226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31, +0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45, +153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65, +163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31, +245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242, +244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8, +207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176, +186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157, +221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194, +179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50, +208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22, +195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146, +119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133, +115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163, +102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36, +0,4,43,79,224,139,16,0,0,0,0,0,0,60,15,192,101,253,152,0,5,109,252,17,98,0, +0,0,0,0,0,7,129,248,12,191,181,0,0,174,63,130,44,64,0,0,0,0,0,0,240,63,1, +151,246,224,0,21,215,240,69,136,0,0,0,0,0,0,0,8,0,50,254,228,0,2,188,254,8, +177,0,0,0,0,0,0,0,1,0,6,95,221,128,0,87,223,193,22,32,0,0,0,0,0,0,8,32,0, +203,251,208,0,11,3,248,34,196,0,0,0,0,0,0,1,4,0,25,127,126,0,1,97,127,4,88, +128,0,0,0,0,0,0,32,128,3,47,240,64,0,44,79,224,139,16,0,0,0,0,0,0,8,16,0, +101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221, +143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16, +124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171, +39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149, +100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10, +40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92, +57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101, +50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168, +95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51, +101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47, +150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113, +108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0, +200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59, +186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121, +101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221, +209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76, +181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116, +98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160, +2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50, +213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209, +155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9, +67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244, +203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81, +70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247, +229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45, +89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27, +10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39, +119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174, +29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130, +243,217,167,30,81,132,65,123,242,211,211,42,228,0, +}; +#elif defined(DUK_USE_DOUBLE_BE) +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = { +105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6, +152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2, +240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75, +14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99, +203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252, +176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86, +148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212, +243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105, +21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70, +145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192, +158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26, +228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14, +202,3,255,254,32,234,3,255,192,0,0,0,0,0,0,119,1,255,192,0,0,0,0,0,0,57, +136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153, +40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223, +200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231, +119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144, +138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12, +166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212, +19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18, +17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136, +100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151, +30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246, +240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46, +236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199, +135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163, +208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31, +240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221, +82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150, +158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157, +135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157, +217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203, +46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238, +230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93, +205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249, +230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16, +237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114, +223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113, +119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5, +195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130, +135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80, +128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175, +61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94, +123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65, +250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47, +102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8, +105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7, +183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66, +15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0, +195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129, +202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101, +131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52, +133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50, +195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28, +121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225, +179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253, +242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151, +148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196, +122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211, +150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138, +48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,15, +253,255,255,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0, +0,0,0,67,168,15,255,0,0,0,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70, +147,58,77,75,48,31,252,0,0,0,0,0,0,34,51,162,199,131,82,77,104,183,228,206, +141,38,116,154,150,96,127,248,0,0,0,0,0,0,0,15,248,192,70,40,0,0,0,0,0,0,0, +0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248, +190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167, +126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64, +247,111,238,56,0,127,199,2,49,72,127,248,0,0,0,0,0,0,180,81,36,4,51,166, +248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105, +244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196, +195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77, +59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32, +80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156, +184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132, +0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126, +238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33, +196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244, +171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62, +94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122, +101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156, +43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121, +113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223, +187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61, +251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231, +151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154, +121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217, +167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100, +43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10, +231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205, +211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3, +208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19, +15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60, +189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43, +224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229, +233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195, +200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144, +24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0, +0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159, +240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230, +115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45, +252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185, +111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221, +143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206, +238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53, +60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85, +165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,64,5,191,10,139,20,87, +105,130,76,156,197,132,4,0,38,187,27,187,85,81,104,28,201,204,160,31,243, +23,33,127,125,28,247,193,102,79,142,202,44,3,255,113,84,118,82,184,47,232, +52,201,241,216,176,139,0,255,111,45,236,84,155,148,58,5,66,76,4,0,146,31, +181,68,66,209,136,61,58,52,170,49,190,202,1,255,53,4,243,51,249,222,108,22, +157,26,85,25,64,63,246,160,158,102,127,59,205,74,7,135,23,53,2,65,48,227, +223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195, +211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15, +47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0, +136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110, +88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0, +21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23, +134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0, +191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,32,98,65,128,0,0, +0,0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144, +60,56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7, +147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3, +252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255, +167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67, +184,2,172,254,0,0,255,171,8,137,144,128,0,0,0,0,0,0,0,68,73,4,195,187,126, +226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31, +0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45, +153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65, +163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31, +245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242, +244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8, +207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176, +186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157, +221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194, +179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50, +208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22, +195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146, +119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133, +115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163, +102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36, +0,4,43,79,224,139,16,15,252,0,0,0,0,0,0,0,101,253,152,0,5,109,252,17,98,1, +255,128,0,0,0,0,0,0,12,191,181,0,0,174,63,130,44,64,63,240,0,0,0,0,0,0,1, +151,246,224,0,21,215,240,69,136,8,0,0,0,0,0,0,0,0,50,254,228,0,2,188,254,8, +177,1,0,0,0,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,32,8,0,0,0,0,0,0,0, +203,251,208,0,11,3,248,34,196,4,1,0,0,0,0,0,0,0,25,127,126,0,1,97,127,4,88, +128,128,32,0,0,0,0,0,0,3,47,240,64,0,44,79,224,139,16,16,8,0,0,0,0,0,0,0, +101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221, +143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16, +124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171, +39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149, +100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10, +40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92, +57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101, +50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168, +95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51, +101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47, +150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113, +108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0, +200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59, +186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121, +101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221, +209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76, +181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116, +98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160, +2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50, +213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209, +155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9, +67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244, +203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81, +70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247, +229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45, +89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27, +10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39, +119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174, +29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130, +243,217,167,30,81,132,65,123,242,211,211,42,228,0, +}; +#elif defined(DUK_USE_DOUBLE_ME) +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = { +105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6, +152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2, +240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75, +14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99, +203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252, +176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86, +148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212, +243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105, +21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70, +145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192, +158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26, +228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14, +202,3,255,254,32,234,0,0,7,195,248,0,0,0,0,119,0,0,3,193,252,0,0,0,0,57, +136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153, +40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223, +200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231, +119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144, +138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12, +166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212, +19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18, +17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136, +100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151, +30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246, +240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46, +236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199, +135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163, +208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31, +240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221, +82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150, +158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157, +135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157, +217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203, +46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238, +230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93, +205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249, +230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16, +237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114, +223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113, +119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5, +195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130, +135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80, +128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175, +61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94, +123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65, +250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47, +102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8, +105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7, +183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66, +15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0, +195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129, +202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101, +131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52, +133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50, +195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28, +121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225, +179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253, +242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151, +148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196, +122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211, +150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138, +48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31, +255,253,239,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0, +64,0,0,3,168,0,0,31,15,224,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70, +147,58,77,75,48,0,0,60,31,192,0,0,0,34,51,162,199,131,82,77,104,183,228, +206,141,38,116,154,150,96,0,0,120,127,128,0,0,0,0,15,248,192,70,40,0,0,0,0, +0,0,0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166, +248,190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231, +167,126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127, +64,247,111,238,56,0,127,199,2,49,72,0,0,248,127,0,0,0,0,180,81,36,4,51,166, +248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105, +244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196, +195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77, +59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32, +80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156, +184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132, +0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126, +238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33, +196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244, +171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62, +94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122, +101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156, +43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121, +113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223, +187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61, +251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231, +151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154, +121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217, +167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100, +43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10, +231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205, +211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3, +208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19, +15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60, +189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43, +224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229, +233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195, +200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144, +24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0, +0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159, +240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230, +115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45, +252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185, +111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221, +143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206, +238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53, +60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85, +165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,10,191,5,64,105,87,20, +139,130,76,156,197,132,11,22,176,36,1,101,91,91,184,28,201,204,160,33,23, +115,31,247,156,253,127,65,102,79,142,202,44,4,113,95,115,255,232,34,182,88, +52,201,241,216,176,139,1,239,47,108,252,59,148,152,86,5,66,76,15,178,16, +148,1,130,212,69,72,61,58,52,170,49,190,202,4,245,7,49,254,105,219,251,52, +22,157,26,85,25,64,158,160,246,63,205,59,127,102,74,7,135,23,53,2,65,48, +227,223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5, +195,211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44, +15,47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0, +136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110, +88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0, +21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23, +134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0, +191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,65,226,32,0,0,0, +0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60, +56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7, +147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3, +252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255, +167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67, +184,2,172,254,0,0,255,171,8,137,144,0,0,0,128,0,0,0,0,68,73,4,195,187,126, +226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31, +0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45, +153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65, +163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31, +245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242, +244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8, +207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176, +186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157, +221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194, +179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50, +208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22, +195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146, +119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133, +115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163, +102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36, +0,4,43,79,224,139,16,0,0,60,15,192,0,0,0,0,101,253,152,0,5,109,252,17,98,0, +0,7,129,248,0,0,0,0,12,191,181,0,0,174,63,130,44,64,0,0,240,63,0,0,0,0,1, +151,246,224,0,21,215,240,69,136,0,0,0,8,0,0,0,0,0,50,254,228,0,2,188,254,8, +177,0,0,0,1,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,0,0,8,32,0,0,0,0,0, +203,251,208,0,11,3,248,34,196,0,0,1,4,0,0,0,0,0,25,127,126,0,1,97,127,4,88, +128,0,0,32,128,0,0,0,0,3,47,240,64,0,44,79,224,139,16,0,0,8,16,0,0,0,0,0, +101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221, +143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16, +124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171, +39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149, +100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10, +40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92, +57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101, +50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168, +95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51, +101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47, +150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113, +108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0, +200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59, +186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121, +101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221, +209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76, +181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116, +98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160, +2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50, +213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209, +155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9, +67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244, +203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81, +70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247, +229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45, +89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27, +10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39, +119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174, +29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130, +243,217,167,30,81,132,65,123,242,211,211,42,228,0, +}; +#else +#error invalid endianness defines +#endif +#endif /* DUK_USE_ROM_OBJECTS */ +/* + * Error, fatal, and panic handling. + */ + +/* include removed: duk_internal.h */ + +#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */ + +#if defined(DUK_USE_VERBOSE_ERRORS) + +DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) { + va_list ap; + char msg[DUK__ERRFMT_BUFSIZE]; + va_start(ap, fmt); + (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap); + msg[sizeof(msg) - 1] = (char) 0; + duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL)); + va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */ +} + +DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) { + duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL)); +} + +#else /* DUK_USE_VERBOSE_ERRORS */ + +DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { + duk_err_create_and_throw(thr, code); +} + +#endif /* DUK_USE_VERBOSE_ERRORS */ + +/* + * Error throwing helpers + */ + +#if defined(DUK_USE_VERBOSE_ERRORS) +#if defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) { + DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)", + expect_name, duk_get_type_name((duk_context *) thr, index), (long) index); +} +#else +DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) { + DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)", + expect_name, duk_push_string_readable((duk_context *) thr, index), (long) index); +} +#endif +DUK_INTERNAL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message); +} +DUK_INTERNAL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index) { + DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_API_ERROR, "invalid stack index %ld", (long) (index)); +} +DUK_INTERNAL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_API_ERROR, message); +} +DUK_INTERNAL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNIMPLEMENTED_ERROR, DUK_STR_UNIMPLEMENTED); +} +#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT) +DUK_INTERNAL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNSUPPORTED_ERROR, DUK_STR_UNSUPPORTED); +} +#endif +DUK_INTERNAL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, DUK_STR_INTERNAL_ERROR); +} +DUK_INTERNAL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, message); +} +DUK_INTERNAL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { + DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ALLOC_ERROR, message); +} +#else +/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW() + * when non-verbose errors are used. + */ +DUK_INTERNAL void duk_err_type(duk_hthread *thr) { + DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_TYPE_ERROR, NULL); +} +DUK_INTERNAL void duk_err_api(duk_hthread *thr) { + DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_API_ERROR, NULL); +} +DUK_INTERNAL void duk_err_range(duk_hthread *thr) { + DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_RANGE_ERROR, NULL); +} +DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) { + DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_SYNTAX_ERROR, NULL); +} +DUK_INTERNAL void duk_err_unimplemented(duk_hthread *thr) { + DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNIMPLEMENTED_ERROR, NULL); +} +DUK_INTERNAL void duk_err_unsupported(duk_hthread *thr) { + DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNSUPPORTED_ERROR, NULL); +} +DUK_INTERNAL void duk_err_internal(duk_hthread *thr) { + DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_INTERNAL_ERROR, NULL); +} +DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) { + DUK_ERROR_RAW(thr, NULL, thr, DUK_ERR_ALLOC_ERROR, NULL); +} +#endif + +/* + * Default fatal error handler + */ + +DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) { + DUK_UNREF(ctx); +#if defined(DUK_USE_FILE_IO) + DUK_FPRINTF(DUK_STDERR, "FATAL %ld: %s\n", (long) code, (const char *) (msg ? msg : "null")); + DUK_FFLUSH(DUK_STDERR); +#else + /* omit print */ +#endif + DUK_D(DUK_DPRINT("default fatal handler called, code %ld -> calling DUK_PANIC()", (long) code)); + DUK_PANIC(code, msg); + DUK_UNREACHABLE(); +} + +/* + * Default panic handler + */ + +#if !defined(DUK_USE_PANIC_HANDLER) +DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) { +#if defined(DUK_USE_FILE_IO) + DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s (" +#if defined(DUK_USE_PANIC_ABORT) + "calling abort" +#elif defined(DUK_USE_PANIC_EXIT) + "calling exit" +#elif defined(DUK_USE_PANIC_SEGFAULT) + "segfaulting on purpose" +#else +#error no DUK_USE_PANIC_xxx macro defined +#endif + ")\n", (long) code, (const char *) (msg ? msg : "null")); + DUK_FFLUSH(DUK_STDERR); +#else + /* omit print */ + DUK_UNREF(code); + DUK_UNREF(msg); +#endif + +#if defined(DUK_USE_PANIC_ABORT) + DUK_ABORT(); +#elif defined(DUK_USE_PANIC_EXIT) + DUK_EXIT(-1); +#elif defined(DUK_USE_PANIC_SEGFAULT) + /* exit() afterwards to satisfy "noreturn" */ + DUK_CAUSE_SEGFAULT(); /* SCANBUILD: "Dereference of null pointer", normal */ + DUK_EXIT(-1); +#else +#error no DUK_USE_PANIC_xxx macro defined +#endif + + DUK_UNREACHABLE(); +} +#endif /* !DUK_USE_PANIC_HANDLER */ + +#undef DUK__ERRFMT_BUFSIZE +/* + * Various Unicode help functions for character classification predicates, + * case conversion, decoding, etc. + */ + +/* include removed: duk_internal.h */ + +/* + * Fast path tables + */ + +#if defined(DUK_USE_IDCHAR_FASTPATH) +DUK_INTERNAL const duk_int8_t duk_is_idchar_tab[128] = { + /* 0: not IdentifierStart or IdentifierPart + * 1: IdentifierStart and IdentifierPart + * -1: IdentifierPart only + */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00...0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10...0x1f */ + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20...0x2f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, /* 0x30...0x3f */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40...0x4f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50...0x5f */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60...0x6f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70...0x7f */ +}; +#endif + +/* + * XUTF-8 and CESU-8 encoding/decoding + */ + +DUK_INTERNAL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) { + duk_uint_fast32_t x = (duk_uint_fast32_t) cp; + if (x < 0x80UL) { + /* 7 bits */ + return 1; + } else if (x < 0x800UL) { + /* 11 bits */ + return 2; + } else if (x < 0x10000UL) { + /* 16 bits */ + return 3; + } else if (x < 0x200000UL) { + /* 21 bits */ + return 4; + } else if (x < 0x4000000UL) { + /* 26 bits */ + return 5; + } else if (x < (duk_ucodepoint_t) 0x80000000UL) { + /* 31 bits */ + return 6; + } else { + /* 36 bits */ + return 7; + } +} + +#if defined(DUK_USE_ASSERTIONS) +DUK_INTERNAL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp) { + duk_uint_fast32_t x = (duk_uint_fast32_t) cp; + if (x < 0x80UL) { + /* 7 bits */ + return 1; + } else if (x < 0x800UL) { + /* 11 bits */ + return 2; + } else if (x < 0x10000UL) { + /* 16 bits */ + return 3; + } else { + /* Encoded as surrogate pair, each encoding to 3 bytes for + * 6 bytes total. Codepoints above U+10FFFF encode as 6 bytes + * too, see duk_unicode_encode_cesu8(). + */ + return 3 + 3; + } +} +#endif /* DUK_USE_ASSERTIONS */ + +DUK_INTERNAL const duk_uint8_t duk_unicode_xutf8_markers[7] = { + 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe +}; + +/* Encode to extended UTF-8; 'out' must have space for at least + * DUK_UNICODE_MAX_XUTF8_LENGTH bytes. Allows encoding of any + * 32-bit (unsigned) codepoint. + */ +DUK_INTERNAL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) { + duk_uint_fast32_t x = (duk_uint_fast32_t) cp; + duk_small_int_t len; + duk_uint8_t marker; + duk_small_int_t i; + + len = duk_unicode_get_xutf8_length(cp); + DUK_ASSERT(len > 0); + + marker = duk_unicode_xutf8_markers[len - 1]; /* 64-bit OK because always >= 0 */ + + i = len; + DUK_ASSERT(i > 0); + do { + i--; + if (i > 0) { + out[i] = (duk_uint8_t) (0x80 + (x & 0x3f)); + x >>= 6; + } else { + /* Note: masking of 'x' is not necessary because of + * range check and shifting -> no bits overlapping + * the marker should be set. + */ + out[0] = (duk_uint8_t) (marker + x); + } + } while (i > 0); + + return len; +} + +/* Encode to CESU-8; 'out' must have space for at least + * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF + * will encode to garbage but won't overwrite the output buffer. + */ +DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) { + duk_uint_fast32_t x = (duk_uint_fast32_t) cp; + duk_small_int_t len; + + if (x < 0x80UL) { + out[0] = (duk_uint8_t) x; + len = 1; + } else if (x < 0x800UL) { + out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f)); + out[1] = (duk_uint8_t) (0x80 + (x & 0x3f)); + len = 2; + } else if (x < 0x10000UL) { + /* surrogate pairs get encoded here */ + out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f)); + out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f)); + out[2] = (duk_uint8_t) (0x80 + (x & 0x3f)); + len = 3; + } else { + /* + * Unicode codepoints above U+FFFF are encoded as surrogate + * pairs here. This ensures that all CESU-8 codepoints are + * 16-bit values as expected in Ecmascript. The surrogate + * pairs always get a 3-byte encoding (each) in CESU-8. + * See: http://en.wikipedia.org/wiki/Surrogate_pair + * + * 20-bit codepoint, 10 bits (A and B) per surrogate pair: + * + * x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB + * sp1 = 0b110110AA AAAAAAAA (0xd800 + ((x >> 10) & 0x3ff)) + * sp2 = 0b110111BB BBBBBBBB (0xdc00 + (x & 0x3ff)) + * + * Encoded into CESU-8: + * + * sp1 -> 0b11101101 (0xe0 + ((sp1 >> 12) & 0x0f)) + * -> 0b1010AAAA (0x80 + ((sp1 >> 6) & 0x3f)) + * -> 0b10AAAAAA (0x80 + (sp1 & 0x3f)) + * sp2 -> 0b11101101 (0xe0 + ((sp2 >> 12) & 0x0f)) + * -> 0b1011BBBB (0x80 + ((sp2 >> 6) & 0x3f)) + * -> 0b10BBBBBB (0x80 + (sp2 & 0x3f)) + * + * Note that 0x10000 must be subtracted first. The code below + * avoids the sp1, sp2 temporaries which saves around 20 bytes + * of code. + */ + + x -= 0x10000UL; + + out[0] = (duk_uint8_t) (0xed); + out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f)); + out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f)); + out[3] = (duk_uint8_t) (0xed); + out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f)); + out[5] = (duk_uint8_t) (0x80 + (x & 0x3f)); + len = 6; + } + + return len; +} + +/* Decode helper. Return zero on error. */ +DUK_INTERNAL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp) { + const duk_uint8_t *p; + duk_uint32_t res; + duk_uint_fast8_t ch; + duk_small_int_t n; + + DUK_UNREF(thr); + + p = *ptr; + if (p < ptr_start || p >= ptr_end) { + goto fail; + } + + /* + * UTF-8 decoder which accepts longer than standard byte sequences. + * This allows full 32-bit code points to be used. + */ + + ch = (duk_uint_fast8_t) (*p++); + if (ch < 0x80) { + /* 0xxx xxxx [7 bits] */ + res = (duk_uint32_t) (ch & 0x7f); + n = 0; + } else if (ch < 0xc0) { + /* 10xx xxxx -> invalid */ + goto fail; + } else if (ch < 0xe0) { + /* 110x xxxx 10xx xxxx [11 bits] */ + res = (duk_uint32_t) (ch & 0x1f); + n = 1; + } else if (ch < 0xf0) { + /* 1110 xxxx 10xx xxxx 10xx xxxx [16 bits] */ + res = (duk_uint32_t) (ch & 0x0f); + n = 2; + } else if (ch < 0xf8) { + /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx [21 bits] */ + res = (duk_uint32_t) (ch & 0x07); + n = 3; + } else if (ch < 0xfc) { + /* 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [26 bits] */ + res = (duk_uint32_t) (ch & 0x03); + n = 4; + } else if (ch < 0xfe) { + /* 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [31 bits] */ + res = (duk_uint32_t) (ch & 0x01); + n = 5; + } else if (ch < 0xff) { + /* 1111 1110 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [36 bits] */ + res = (duk_uint32_t) (0); + n = 6; + } else { + /* 8-byte format could be: + * 1111 1111 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [41 bits] + * + * However, this format would not have a zero bit following the + * leading one bits and would not allow 0xFF to be used as an + * "invalid xutf-8" marker for internal keys. Further, 8-byte + * encodings (up to 41 bit code points) are not currently needed. + */ + goto fail; + } + + DUK_ASSERT(p >= ptr_start); /* verified at beginning */ + if (p + n > ptr_end) { + /* check pointer at end */ + goto fail; + } + + while (n > 0) { + DUK_ASSERT(p >= ptr_start && p < ptr_end); + res = res << 6; + res += (duk_uint32_t) ((*p++) & 0x3f); + n--; + } + + *ptr = p; + *out_cp = res; + return 1; + + fail: + return 0; +} + +/* used by e.g. duk_regexp_executor.c, string built-ins */ +DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end) { + duk_ucodepoint_t cp; + + if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) { + return cp; + } + DUK_ERROR_INTERNAL(thr, "utf-8 decode failed"); /* XXX: 'internal error' is a bit of a misnomer */ + DUK_UNREACHABLE(); + return 0; +} + +/* Compute (extended) utf-8 length without codepoint encoding validation, + * used for string interning. + * + * NOTE: This algorithm is performance critical, more so than string hashing + * in some cases. It is needed when interning a string and needs to scan + * every byte of the string with no skipping. Having an ASCII fast path + * is useful if possible in the algorithm. The current algorithms were + * chosen from several variants, based on x64 gcc -O2 testing. See: + * https://github.com/svaarala/duktape/pull/422 + * + * NOTE: must match src/dukutil.py:duk_unicode_unvalidated_utf8_length(). + */ + +#if defined(DUK_USE_PREFER_SIZE) +/* Small variant; roughly 150 bytes smaller than the fast variant. */ +DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) { + const duk_uint8_t *p; + const duk_uint8_t *p_end; + duk_size_t ncont; + duk_size_t clen; + + p = data; + p_end = data + blen; + ncont = 0; + while (p != p_end) { + duk_uint8_t x; + x = *p++; + if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { + ncont++; + } + } + + DUK_ASSERT(ncont <= blen); + clen = blen - ncont; + DUK_ASSERT(clen <= blen); + return clen; +} +#else /* DUK_USE_PREFER_SIZE */ +/* This seems like a good overall approach. Fast path for ASCII in 4 byte + * blocks. + */ +DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) { + const duk_uint8_t *p; + const duk_uint8_t *p_end; + const duk_uint32_t *p32_end; + const duk_uint32_t *p32; + duk_size_t ncont; + duk_size_t clen; + + ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */ + p = data; + p_end = data + blen; + if (blen < 16) { + goto skip_fastpath; + } + + /* Align 'p' to 4; the input data may have arbitrary alignment. + * End of string check not needed because blen >= 16. + */ + while (((duk_size_t) (const void *) p) & 0x03U) { + duk_uint8_t x; + x = *p++; + if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { + ncont++; + } + } + + /* Full, aligned 4-byte reads. */ + p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03))); + p32 = (const duk_uint32_t *) (const void *) p; + while (p32 != (const duk_uint32_t *) p32_end) { + duk_uint32_t x; + x = *p32++; + if (DUK_LIKELY((x & 0x80808080UL) == 0)) { + ; /* ASCII fast path */ + } else { + /* Flip highest bit of each byte which changes + * the bit pattern 10xxxxxx into 00xxxxxx which + * allows an easy bit mask test. + */ + x ^= 0x80808080UL; + if (DUK_UNLIKELY(!(x & 0xc0000000UL))) { + ncont++; + } + if (DUK_UNLIKELY(!(x & 0x00c00000UL))) { + ncont++; + } + if (DUK_UNLIKELY(!(x & 0x0000c000UL))) { + ncont++; + } + if (DUK_UNLIKELY(!(x & 0x000000c0UL))) { + ncont++; + } + } + } + p = (const duk_uint8_t *) p32; + /* Fall through to handle the rest. */ + + skip_fastpath: + while (p != p_end) { + duk_uint8_t x; + x = *p++; + if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { + ncont++; + } + } + + DUK_ASSERT(ncont <= blen); + clen = blen - ncont; + DUK_ASSERT(clen <= blen); + return clen; +} +#endif /* DUK_USE_PREFER_SIZE */ + +/* + * Unicode range matcher + * + * Matches a codepoint against a packed bitstream of character ranges. + * Used for slow path Unicode matching. + */ + +/* Must match src/extract_chars.py, generate_match_table3(). */ +DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) { + duk_uint32_t t; + + t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4); + if (t <= 0x0eU) { + return t; + } + t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8); + if (t <= 0xfdU) { + return t + 0x0f; + } + if (t == 0xfeU) { + t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12); + return t + 0x0fU + 0xfeU; + } else { + t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24); + return t + 0x0fU + 0xfeU + 0x1000UL; + } +} + +DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) { + duk_bitdecoder_ctx bd_ctx; + duk_codepoint_t prev_re; + + DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); + bd_ctx.data = (const duk_uint8_t *) unitab; + bd_ctx.length = (duk_size_t) unilen; + + prev_re = 0; + for (;;) { + duk_codepoint_t r1, r2; + r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx); + if (r1 == 0) { + break; + } + r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx); + + r1 = prev_re + r1; + r2 = r1 + r2; + prev_re = r2; + + /* [r1,r2] is the range */ + + DUK_DDD(DUK_DDDPRINT("duk__uni_range_match: cp=%06lx range=[0x%06lx,0x%06lx]", + (unsigned long) cp, (unsigned long) r1, (unsigned long) r2)); + if (cp >= r1 && cp <= r2) { + return 1; + } + } + + return 0; +} + +/* + * "WhiteSpace" production check. + */ + +DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) { + /* + * E5 Section 7.2 specifies six characters specifically as + * white space: + * + * 0009;;Cc;0;S;;;;;N;CHARACTER TABULATION;;;; + * 000B;;Cc;0;S;;;;;N;LINE TABULATION;;;; + * 000C;;Cc;0;WS;;;;;N;FORM FEED (FF);;;; + * 0020;SPACE;Zs;0;WS;;;;;N;;;;; + * 00A0;NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;NON-BREAKING SPACE;;;; + * FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; + * + * It also specifies any Unicode category 'Zs' characters as white + * space. These can be extracted with the "src/extract_chars.py" script. + * Current result: + * + * RAW OUTPUT: + * =========== + * 0020;SPACE;Zs;0;WS;;;;;N;;;;; + * 00A0;NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;NON-BREAKING SPACE;;;; + * 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; + * 180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;; + * 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;; + * 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;; + * 2002;EN SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 2003;EM SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 2004;THREE-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 2005;FOUR-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 2006;SIX-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 2007;FIGURE SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 2008;PUNCTUATION SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 2009;THIN SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 200A;HAIR SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 202F;NARROW NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;;;;; + * 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS; 0020;;;;N;;;;; + * 3000;IDEOGRAPHIC SPACE;Zs;0;WS; 0020;;;;N;;;;; + * + * RANGES: + * ======= + * 0x0020 + * 0x00a0 + * 0x1680 + * 0x180e + * 0x2000 ... 0x200a + * 0x202f + * 0x205f + * 0x3000 + * + * A manual decoder (below) is probably most compact for this. + */ + + duk_uint_fast8_t lo; + duk_uint_fast32_t hi; + + /* cp == -1 (EOF) never matches and causes return value 0 */ + + lo = (duk_uint_fast8_t) (cp & 0xff); + hi = (duk_uint_fast32_t) (cp >> 8); /* does not fit into an uchar */ + + if (hi == 0x0000UL) { + if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU || + lo == 0x20U || lo == 0xa0U) { + return 1; + } + } else if (hi == 0x0020UL) { + if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) { + return 1; + } + } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L || + cp == 0xfeffL) { + return 1; + } + + return 0; +} + +/* + * "LineTerminator" production check. + */ + +DUK_INTERNAL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) { + /* + * E5 Section 7.3 + * + * A LineTerminatorSequence essentially merges sequences + * into a single line terminator. This must be handled by the caller. + */ + + if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L || + cp == 0x2029L) { + return 1; + } + + return 0; +} + +/* + * "IdentifierStart" production check. + */ + +DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) { + /* + * E5 Section 7.6: + * + * IdentifierStart: + * UnicodeLetter + * $ + * _ + * \ UnicodeEscapeSequence + * + * IdentifierStart production has one multi-character production: + * + * \ UnicodeEscapeSequence + * + * The '\' character is -not- matched by this function. Rather, the caller + * should decode the escape and then call this function to check whether the + * decoded character is acceptable (see discussion in E5 Section 7.6). + * + * The "UnicodeLetter" alternative of the production allows letters + * from various Unicode categories. These can be extracted with the + * "src/extract_chars.py" script. + * + * Because the result has hundreds of Unicode codepoint ranges, matching + * for any values >= 0x80 are done using a very slow range-by-range scan + * and a packed range format. + * + * The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because + * it matters the most. The ASCII related ranges of IdentifierStart are: + * + * 0x0041 ... 0x005a ['A' ... 'Z'] + * 0x0061 ... 0x007a ['a' ... 'z'] + * 0x0024 ['$'] + * 0x005f ['_'] + */ + + /* ASCII (and EOF) fast path -- quick accept and reject */ + if (cp <= 0x7fL) { +#if defined(DUK_USE_IDCHAR_FASTPATH) + return (cp >= 0) && (duk_is_idchar_tab[cp] > 0); +#else + if ((cp >= 'a' && cp <= 'z') || + (cp >= 'A' && cp <= 'Z') || + cp == '_' || cp == '$') { + return 1; + } + return 0; +#endif + } + + /* Non-ASCII slow path (range-by-range linear comparison), very slow */ + +#ifdef DUK_USE_SOURCE_NONBMP + if (duk__uni_range_match(duk_unicode_ids_noa, + (duk_size_t) sizeof(duk_unicode_ids_noa), + (duk_codepoint_t) cp)) { + return 1; + } + return 0; +#else + if (cp < 0x10000L) { + if (duk__uni_range_match(duk_unicode_ids_noabmp, + sizeof(duk_unicode_ids_noabmp), + (duk_codepoint_t) cp)) { + return 1; + } + return 0; + } else { + /* without explicit non-BMP support, assume non-BMP characters + * are always accepted as identifier characters. + */ + return 1; + } +#endif +} + +/* + * "IdentifierPart" production check. + */ + +DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) { + /* + * E5 Section 7.6: + * + * IdentifierPart: + * IdentifierStart + * UnicodeCombiningMark + * UnicodeDigit + * UnicodeConnectorPunctuation + * [U+200C] + * [U+200D] + * + * IdentifierPart production has one multi-character production + * as part of its IdentifierStart alternative. The '\' character + * of an escape sequence is not matched here, see discussion in + * duk_unicode_is_identifier_start(). + * + * To match non-ASCII characters (codepoints >= 0x80), a very slow + * linear range-by-range scan is used. The codepoint is first compared + * to the IdentifierStart ranges, and if it doesn't match, then to a + * set consisting of code points in IdentifierPart but not in + * IdentifierStart. This is done to keep the unicode range data small, + * at the expense of speed. + * + * The ASCII fast path consists of: + * + * 0x0030 ... 0x0039 ['0' ... '9', UnicodeDigit] + * 0x0041 ... 0x005a ['A' ... 'Z', IdentifierStart] + * 0x0061 ... 0x007a ['a' ... 'z', IdentifierStart] + * 0x0024 ['$', IdentifierStart] + * 0x005f ['_', IdentifierStart and + * UnicodeConnectorPunctuation] + * + * UnicodeCombiningMark has no code points <= 0x7f. + * + * The matching code reuses the "identifier start" tables, and then + * consults a separate range set for characters in "identifier part" + * but not in "identifier start". These can be extracted with the + * "src/extract_chars.py" script. + * + * UnicodeCombiningMark -> categories Mn, Mc + * UnicodeDigit -> categories Nd + * UnicodeConnectorPunctuation -> categories Pc + */ + + /* ASCII (and EOF) fast path -- quick accept and reject */ + if (cp <= 0x7fL) { +#if defined(DUK_USE_IDCHAR_FASTPATH) + return (cp >= 0) && (duk_is_idchar_tab[cp] != 0); +#else + if ((cp >= 'a' && cp <= 'z') || + (cp >= 'A' && cp <= 'Z') || + (cp >= '0' && cp <= '9') || + cp == '_' || cp == '$') { + return 1; + } + return 0; +#endif + } + + /* Non-ASCII slow path (range-by-range linear comparison), very slow */ + +#ifdef DUK_USE_SOURCE_NONBMP + if (duk__uni_range_match(duk_unicode_ids_noa, + sizeof(duk_unicode_ids_noa), + (duk_codepoint_t) cp) || + duk__uni_range_match(duk_unicode_idp_m_ids_noa, + sizeof(duk_unicode_idp_m_ids_noa), + (duk_codepoint_t) cp)) { + return 1; + } + return 0; +#else + if (cp < 0x10000L) { + if (duk__uni_range_match(duk_unicode_ids_noabmp, + sizeof(duk_unicode_ids_noabmp), + (duk_codepoint_t) cp) || + duk__uni_range_match(duk_unicode_idp_m_ids_noabmp, + sizeof(duk_unicode_idp_m_ids_noabmp), + (duk_codepoint_t) cp)) { + return 1; + } + return 0; + } else { + /* without explicit non-BMP support, assume non-BMP characters + * are always accepted as identifier characters. + */ + return 1; + } +#endif +} + +/* + * Unicode letter check. + */ + +DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) { + /* + * Unicode letter is now taken to be the categories: + * + * Lu, Ll, Lt, Lm, Lo + * + * (Not sure if this is exactly correct.) + * + * The ASCII fast path consists of: + * + * 0x0041 ... 0x005a ['A' ... 'Z'] + * 0x0061 ... 0x007a ['a' ... 'z'] + */ + + /* ASCII (and EOF) fast path -- quick accept and reject */ + if (cp <= 0x7fL) { + if ((cp >= 'a' && cp <= 'z') || + (cp >= 'A' && cp <= 'Z')) { + return 1; + } + return 0; + } + + /* Non-ASCII slow path (range-by-range linear comparison), very slow */ + +#ifdef DUK_USE_SOURCE_NONBMP + if (duk__uni_range_match(duk_unicode_ids_noa, + sizeof(duk_unicode_ids_noa), + (duk_codepoint_t) cp) && + !duk__uni_range_match(duk_unicode_ids_m_let_noa, + sizeof(duk_unicode_ids_m_let_noa), + (duk_codepoint_t) cp)) { + return 1; + } + return 0; +#else + if (cp < 0x10000L) { + if (duk__uni_range_match(duk_unicode_ids_noabmp, + sizeof(duk_unicode_ids_noabmp), + (duk_codepoint_t) cp) && + !duk__uni_range_match(duk_unicode_ids_m_let_noabmp, + sizeof(duk_unicode_ids_m_let_noabmp), + (duk_codepoint_t) cp)) { + return 1; + } + return 0; + } else { + /* without explicit non-BMP support, assume non-BMP characters + * are always accepted as letters. + */ + return 1; + } +#endif +} + +/* + * Complex case conversion helper which decodes a bit-packed conversion + * control stream generated by unicode/extract_caseconv.py. The conversion + * is very slow because it runs through the conversion data in a linear + * fashion to save space (which is why ASCII characters have a special + * fast path before arriving here). + * + * The particular bit counts etc have been determined experimentally to + * be small but still sufficient, and must match the Python script + * (src/extract_caseconv.py). + * + * The return value is the case converted codepoint or -1 if the conversion + * results in multiple characters (this is useful for regexp Canonicalization + * operation). If 'buf' is not NULL, the result codepoint(s) are also + * appended to the hbuffer. + * + * Context and locale specific rules must be checked before consulting + * this function. + */ + +DUK_LOCAL +duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr, + duk_bufwriter_ctx *bw, + duk_codepoint_t cp, + duk_bitdecoder_ctx *bd_ctx) { + duk_small_int_t skip = 0; + duk_small_int_t n; + duk_small_int_t t; + duk_small_int_t count; + duk_codepoint_t tmp_cp; + duk_codepoint_t start_i; + duk_codepoint_t start_o; + + DUK_UNREF(thr); + DUK_ASSERT(bd_ctx != NULL); + + DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp)); + + /* range conversion with a "skip" */ + DUK_DDD(DUK_DDDPRINT("checking ranges")); + for (;;) { + skip++; + n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6); + if (n == 0x3f) { + /* end marker */ + break; + } + DUK_DDD(DUK_DDDPRINT("skip=%ld, n=%ld", (long) skip, (long) n)); + + while (n--) { + start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); + start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); + count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7); + DUK_DDD(DUK_DDDPRINT("range: start_i=%ld, start_o=%ld, count=%ld, skip=%ld", + (long) start_i, (long) start_o, (long) count, (long) skip)); + + if (cp >= start_i) { + tmp_cp = cp - start_i; /* always >= 0 */ + if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip && + (tmp_cp % (duk_codepoint_t) skip) == 0) { + DUK_DDD(DUK_DDDPRINT("range matches input codepoint")); + cp = start_o + tmp_cp; + goto single; + } + } + } + } + + /* 1:1 conversion */ + n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6); + DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n)); + while (n--) { + start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); + start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); + DUK_DDD(DUK_DDDPRINT("1:1 conversion %ld -> %ld", (long) start_i, (long) start_o)); + if (cp == start_i) { + DUK_DDD(DUK_DDDPRINT("1:1 matches input codepoint")); + cp = start_o; + goto single; + } + } + + /* complex, multicharacter conversion */ + n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7); + DUK_DDD(DUK_DDDPRINT("checking 1:n conversions (count %ld)", (long) n)); + while (n--) { + start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); + t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2); + DUK_DDD(DUK_DDDPRINT("1:n conversion %ld -> %ld chars", (long) start_i, (long) t)); + if (cp == start_i) { + DUK_DDD(DUK_DDDPRINT("1:n matches input codepoint")); + if (bw != NULL) { + while (t--) { + tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); + DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) tmp_cp); + } + } + return -1; + } else { + while (t--) { + (void) duk_bd_decode(bd_ctx, 16); + } + } + } + + /* default: no change */ + DUK_DDD(DUK_DDDPRINT("no rule matches, output is same as input")); + /* fall through */ + + single: + if (bw != NULL) { + DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp); + } + return cp; +} + +/* + * Case conversion helper, with context/local sensitivity. + * For proper case conversion, one needs to know the character + * and the preceding and following characters, as well as + * locale/language. + */ + +/* XXX: add 'language' argument when locale/language sensitive rule + * support added. + */ +DUK_LOCAL +duk_codepoint_t duk__case_transform_helper(duk_hthread *thr, + duk_bufwriter_ctx *bw, + duk_codepoint_t cp, + duk_codepoint_t prev, + duk_codepoint_t next, + duk_bool_t uppercase) { + duk_bitdecoder_ctx bd_ctx; + + /* fast path for ASCII */ + if (cp < 0x80L) { + /* XXX: there are language sensitive rules for the ASCII range. + * If/when language/locale support is implemented, they need to + * be implemented here for the fast path. There are no context + * sensitive rules for ASCII range. + */ + + if (uppercase) { + if (cp >= 'a' && cp <= 'z') { + cp = cp - 'a' + 'A'; + } + } else { + if (cp >= 'A' && cp <= 'Z') { + cp = cp - 'A' + 'a'; + } + } + + if (bw != NULL) { + DUK_BW_WRITE_RAW_U8(thr, bw, (duk_uint8_t) cp); + } + return cp; + } + + /* context and locale specific rules which cannot currently be represented + * in the caseconv bitstream: hardcoded rules in C + */ + if (uppercase) { + /* XXX: turkish / azeri */ + } else { + /* + * Final sigma context specific rule. This is a rather tricky + * rule and this handling is probably not 100% correct now. + * The rule is not locale/language specific so it is supported. + */ + + if (cp == 0x03a3L && /* U+03A3 = GREEK CAPITAL LETTER SIGMA */ + duk_unicode_is_letter(prev) && /* prev exists and is not a letter */ + !duk_unicode_is_letter(next)) { /* next does not exist or next is not a letter */ + /* Capital sigma occurred at "end of word", lowercase to + * U+03C2 = GREEK SMALL LETTER FINAL SIGMA. Otherwise + * fall through and let the normal rules lowercase it to + * U+03C3 = GREEK SMALL LETTER SIGMA. + */ + cp = 0x03c2L; + goto singlechar; + } + + /* XXX: lithuanian not implemented */ + /* XXX: lithuanian, explicit dot rules */ + /* XXX: turkish / azeri, lowercase rules */ + } + + /* 1:1 or special conversions, but not locale/context specific: script generated rules */ + DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); + if (uppercase) { + bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc; + bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc); + } else { + bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc; + bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc); + } + return duk__slow_case_conversion(thr, bw, cp, &bd_ctx); + + singlechar: + if (bw != NULL) { + DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp); + } + return cp; + + /* unused now, not needed until Turkish/Azeri */ +#if 0 + nochar: + return -1; +#endif +} + +/* + * Replace valstack top with case converted version. + */ + +DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase) { + duk_context *ctx = (duk_context *) thr; + duk_hstring *h_input; + duk_bufwriter_ctx bw_alloc; + duk_bufwriter_ctx *bw; + const duk_uint8_t *p, *p_start, *p_end; + duk_codepoint_t prev, curr, next; + + h_input = duk_require_hstring(ctx, -1); + DUK_ASSERT(h_input != NULL); + + bw = &bw_alloc; + DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); + + /* [ ... input buffer ] */ + + p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); + p = p_start; + + prev = -1; DUK_UNREF(prev); + curr = -1; + next = -1; + for (;;) { + prev = curr; + curr = next; + next = -1; + if (p < p_end) { + next = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); + } else { + /* end of input and last char has been processed */ + if (curr < 0) { + break; + } + } + + /* on first round, skip */ + if (curr >= 0) { + /* XXX: could add a fast path to process chunks of input codepoints, + * but relative benefit would be quite small. + */ + + /* Ensure space for maximum multi-character result; estimate is overkill. */ + DUK_BW_ENSURE(thr, bw, 8 * DUK_UNICODE_MAX_XUTF8_LENGTH); + + duk__case_transform_helper(thr, + bw, + (duk_codepoint_t) curr, + prev, + next, + uppercase); + } + } + + DUK_BW_COMPACT(thr, bw); + duk_to_string(ctx, -1); /* invalidates h_buf pointer */ + duk_remove(ctx, -2); +} + +#ifdef DUK_USE_REGEXP_SUPPORT + +/* + * Canonicalize() abstract operation needed for canonicalization of individual + * codepoints during regexp compilation and execution, see E5 Section 15.10.2.8. + * Note that codepoints are canonicalized one character at a time, so no context + * specific rules can apply. Locale specific rules can apply, though. + */ + +DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) { +#if defined(DUK_USE_REGEXP_CANON_WORKAROUND) + /* Fast canonicalization lookup at the cost of 128kB footprint. */ + DUK_ASSERT(cp >= 0); + DUK_UNREF(thr); + if (DUK_LIKELY(cp < 0x10000L)) { + return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp]; + } + return cp; +#else /* DUK_USE_REGEXP_CANON_WORKAROUND */ + duk_codepoint_t y; + + y = duk__case_transform_helper(thr, + NULL, /* NULL is allowed, no output */ + cp, /* curr char */ + -1, /* prev char */ + -1, /* next char */ + 1); /* uppercase */ + + if ((y < 0) || (cp >= 0x80 && y < 0x80)) { + /* multiple codepoint conversion or non-ASCII mapped to ASCII + * --> leave as is. + */ + return cp; + } + + return y; +#endif /* DUK_USE_REGEXP_CANON_WORKAROUND */ +} + +/* + * E5 Section 15.10.2.6 "IsWordChar" abstract operation. Assume + * x < 0 for characters read outside the string. + */ + +DUK_INTERNAL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) { + /* + * Note: the description in E5 Section 15.10.2.6 has a typo, it + * contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_]. + */ + if ((x >= '0' && x <= '9') || + (x >= 'a' && x <= 'z') || + (x >= 'A' && x <= 'Z') || + (x == '_')) { + return 1; + } + return 0; +} + +/* + * Regexp range tables + */ + +/* exposed because lexer needs these too */ +DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_digit[2] = { + (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL, +}; +DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_white[22] = { + (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL, + (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL, + (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL, + (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL, + (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL, + (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL, + (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL, + (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL, + (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL, + (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL, + (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL, +}; +DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_wordchar[8] = { + (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL, + (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL, + (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL, + (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL, +}; +DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_digit[4] = { + (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL, + (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL, +}; +DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_white[24] = { + (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL, + (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL, + (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL, + (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL, + (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL, + (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL, + (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL, + (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL, + (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL, + (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL, + (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL, + (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL, +}; +DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = { + (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL, + (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL, + (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL, + (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL, + (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL, +}; + +#endif /* DUK_USE_REGEXP_SUPPORT */ +/* + * Misc util stuff + */ + +/* include removed: duk_internal.h */ + +/* + * Lowercase digits for radix values 2 to 36. Also doubles as lowercase + * hex nybble table. + */ + +DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = { + DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, + DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, + DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B, + DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F, + DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J, + DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N, + DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R, + DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V, + DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z +}; + +DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = { + DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, + DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, + DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B, + DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F +}; + +/* + * Table for hex decoding ASCII hex digits + */ + +DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = { + /* -1 if invalid */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */ +}; + +#if defined(DUK_USE_HEX_FASTPATH) +/* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */ +DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */ + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */ + -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */ + -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */ +}; +#endif + +/* + * Table for hex encoding bytes + */ + +#if defined(DUK_USE_HEX_FASTPATH) +/* Lookup to encode one byte directly into 2 characters: + * + * def genhextab(bswap): + * for i in xrange(256): + * t = chr(i).encode('hex') + * if bswap: + * t = t[1] + t[0] + * print('0x' + t.encode('hex') + 'U') + * print('big endian'); genhextab(False) + * print('little endian'); genhextab(True) +*/ +DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = { +#if defined(DUK_USE_INTEGER_BE) + 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U, + 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U, + 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U, + 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U, + 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U, + 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U, + 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U, + 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U, + 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U, + 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U, + 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U, + 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U, + 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U, + 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U, + 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U, + 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U, + 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U, + 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U, + 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U, + 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U, + 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U, + 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U, + 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U, + 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U, + 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U, + 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U, + 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U, + 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U, + 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U, + 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U, + 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U, + 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U +#else /* DUK_USE_INTEGER_BE */ + 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U, + 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U, + 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U, + 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U, + 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U, + 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U, + 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U, + 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U, + 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U, + 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U, + 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U, + 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U, + 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U, + 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U, + 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U, + 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U, + 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U, + 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U, + 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U, + 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U, + 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U, + 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U, + 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U, + 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U, + 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U, + 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U, + 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U, + 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U, + 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U, + 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U, + 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U, + 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U +#endif /* DUK_USE_INTEGER_BE */ +}; +#endif /* DUK_USE_HEX_FASTPATH */ + +/* + * Table for base-64 encoding + */ + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = { + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */ + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */ + 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */ + 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */ +}; +#endif /* DUK_USE_BASE64_FASTPATH */ + +/* + * Table for base-64 decoding + */ + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = { + /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */ + -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */ + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */ + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */ + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */ +}; +#endif /* DUK_USE_BASE64_FASTPATH */ + +/* + * Arbitrary byteswap for potentially unaligned values + * + * Used to byteswap pointers e.g. in debugger code. + */ + +#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */ +DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) { + duk_uint8_t tmp; + duk_uint8_t *q = p + len - 1; + + while (p - q < 0) { + tmp = *p; + *p = *q; + *q = tmp; + p++; + q--; + } +} +#endif +/* + * Round a number upwards to a prime (not usually the nearest one). + * + * Uses a table of successive 32-bit primes whose ratio is roughly + * constant. This keeps the relative upwards 'rounding error' bounded + * and the data size small. A simple 'predict-correct' compression is + * used to compress primes to one byte per prime. See genhashsizes.py + * for details. + * + * The minimum prime returned here must be coordinated with the possible + * probe sequence steps in duk_hobject and duk_heap stringtable. + */ + +/* include removed: duk_internal.h */ + +/* Awkward inclusion condition: drop out of compilation if not needed by any + * call site: object hash part or probing stringtable. + */ +#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) + +/* hash size ratio goal, must match genhashsizes.py */ +#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */ + +/* prediction corrections for prime list (see genhashsizes.py) */ +DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = { + 17, /* minimum prime */ + 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3, + 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5, + 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29, + 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12, + 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30, + 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41, + 10, 23, 16, 9, 2, + -1 +}; + +/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long + * (DUK_UTIL_GET_HASH_PROBE_STEP macro). + */ +DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = { + 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107, + 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199 +}; + +DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) { + const duk_int8_t *p = duk__hash_size_corrections; + duk_uint32_t curr; + + curr = (duk_uint32_t) *p++; + for (;;) { + duk_small_int_t t = (duk_small_int_t) *p++; + if (t < 0) { + /* may happen if size is very close to 2^32-1 */ + break; + } + + /* prediction: portable variant using doubles if 64-bit values not available */ +#ifdef DUK_USE_64BIT_OPS + curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10); +#else + /* 32-bit x 11-bit = 43-bit, fits accurately into a double */ + curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0); +#endif + + /* correction */ + curr += t; + + DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr)); + + if (curr >= size) { + return curr; + } + } + return 0; +} + +#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */ +/* + * Hobject Ecmascript [[Class]]. + */ + +/* include removed: duk_internal.h */ + +#if (DUK_STRIDX_UC_ARGUMENTS > 255) +#error constant too large +#endif +#if (DUK_STRIDX_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UC_BOOLEAN > 255) +#error constant too large +#endif +#if (DUK_STRIDX_DATE > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UC_ERROR > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UC_FUNCTION > 255) +#error constant too large +#endif +#if (DUK_STRIDX_JSON > 255) +#error constant too large +#endif +#if (DUK_STRIDX_MATH > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UC_NUMBER > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UC_OBJECT > 255) +#error constant too large +#endif +#if (DUK_STRIDX_REG_EXP > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UC_STRING > 255) +#error constant too large +#endif +#if (DUK_STRIDX_GLOBAL > 255) +#error constant too large +#endif +#if (DUK_STRIDX_OBJ_ENV > 255) +#error constant too large +#endif +#if (DUK_STRIDX_DEC_ENV > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UC_BUFFER > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UC_POINTER > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UC_THREAD > 255) +#error constant too large +#endif +#if (DUK_STRIDX_ARRAY_BUFFER > 255) +#error constant too large +#endif +#if (DUK_STRIDX_DATA_VIEW > 255) +#error constant too large +#endif +#if (DUK_STRIDX_INT8_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UINT8_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_INT16_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UINT16_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_INT32_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_UINT32_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_FLOAT32_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_FLOAT64_ARRAY > 255) +#error constant too large +#endif +#if (DUK_STRIDX_EMPTY_STRING > 255) +#error constant too large +#endif + +/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */ +DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = { + DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ + DUK_STRIDX_UC_ARGUMENTS, + DUK_STRIDX_ARRAY, + DUK_STRIDX_UC_BOOLEAN, + DUK_STRIDX_DATE, + DUK_STRIDX_UC_ERROR, + DUK_STRIDX_UC_FUNCTION, + DUK_STRIDX_JSON, + DUK_STRIDX_MATH, + DUK_STRIDX_UC_NUMBER, + DUK_STRIDX_UC_OBJECT, + DUK_STRIDX_REG_EXP, + DUK_STRIDX_UC_STRING, + DUK_STRIDX_GLOBAL, + DUK_STRIDX_OBJ_ENV, + DUK_STRIDX_DEC_ENV, + DUK_STRIDX_UC_BUFFER, + DUK_STRIDX_UC_POINTER, + DUK_STRIDX_UC_THREAD, + DUK_STRIDX_ARRAY_BUFFER, + DUK_STRIDX_DATA_VIEW, + DUK_STRIDX_INT8_ARRAY, + DUK_STRIDX_UINT8_ARRAY, + DUK_STRIDX_UINT8_CLAMPED_ARRAY, + DUK_STRIDX_INT16_ARRAY, + DUK_STRIDX_UINT16_ARRAY, + DUK_STRIDX_INT32_ARRAY, + DUK_STRIDX_UINT32_ARRAY, + DUK_STRIDX_FLOAT32_ARRAY, + DUK_STRIDX_FLOAT64_ARRAY, + DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ + DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ +}; +/* + * Default allocation functions. + * + * Assumes behavior such as malloc allowing zero size, yielding + * a NULL or a unique pointer which is a no-op for free. + */ + +/* include removed: duk_internal.h */ + +#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) +DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) { + void *res; + DUK_UNREF(udata); + res = DUK_ANSI_MALLOC(size); + DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p", + (unsigned long) size, (void *) res)); + return res; +} + +DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) { + void *res; + DUK_UNREF(udata); + res = DUK_ANSI_REALLOC(ptr, newsize); + DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p", + (void *) ptr, (unsigned long) newsize, (void *) res)); + return res; +} + +DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) { + DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr)); + DUK_UNREF(udata); + DUK_ANSI_FREE(ptr); +} +#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */ +/* + * Buffer + */ + +/* include removed: duk_internal.h */ + +DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hbuffer_dynamic *h; + + DUK_ASSERT_CTX_VALID(ctx); + + h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index); + DUK_ASSERT(h != NULL); + + if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { + DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); + } + + /* maximum size check is handled by callee */ + duk_hbuffer_resize(thr, h, new_size); + + return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); +} + +DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hbuffer_dynamic *h; + void *ptr; + duk_size_t sz; + + DUK_ASSERT(ctx != NULL); + + h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index); + DUK_ASSERT(h != NULL); + + if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { + DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); + } + + /* Forget the previous allocation, setting size to 0 and alloc to + * NULL. Caller is responsible for freeing the previous allocation. + * Getting the allocation and clearing it is done in the same API + * call to avoid any chance of a realloc. + */ + ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); + sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h); + if (out_size) { + *out_size = sz; + } + DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h); + DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0); + + return ptr; +} + +DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hbuffer_external *h; + + DUK_ASSERT(ctx != NULL); + + h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, index); + DUK_ASSERT(h != NULL); + + if (!DUK_HBUFFER_HAS_EXTERNAL(h)) { + DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); + } + DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h)); + + DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr); + DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len); +} +/* + * Bytecode dump/load + * + * The bytecode load primitive is more important performance-wise than the + * dump primitive. + * + * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be + * memory safe for invalid arguments - caller beware! There's little point + * in trying to achieve memory safety unless bytecode instructions are also + * validated which is not easy to do with indirect register references etc. + */ + +/* include removed: duk_internal.h */ + +#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT) + +#define DUK__SER_MARKER 0xff +#define DUK__SER_VERSION 0x00 +#define DUK__SER_STRING 0x00 +#define DUK__SER_NUMBER 0x01 +#define DUK__BYTECODE_INITIAL_ALLOC 256 + +/* + * Dump/load helpers, xxx_raw() helpers do no buffer checks + */ + +DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_context *ctx, duk_uint8_t *p) { + duk_uint32_t len; + + len = DUK_RAW_READ_U32_BE(p); + duk_push_lstring(ctx, (const char *) p, len); + p += len; + return p; +} + +DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) { + duk_uint32_t len; + duk_uint8_t *buf; + + len = DUK_RAW_READ_U32_BE(p); + buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len); + DUK_ASSERT(buf != NULL); + DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len); + p += len; + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) { + duk_size_t len; + duk_uint32_t tmp32; + + DUK_ASSERT(h != NULL); + + len = DUK_HSTRING_GET_BYTELEN(h); + DUK_ASSERT(len <= 0xffffffffUL); /* string limits */ + tmp32 = (duk_uint32_t) len; + DUK_RAW_WRITE_U32_BE(p, tmp32); + DUK_MEMCPY((void *) p, + (const void *) DUK_HSTRING_GET_DATA(h), + len); + p += len; + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) { + duk_size_t len; + duk_uint32_t tmp32; + + DUK_ASSERT(thr != NULL); + DUK_ASSERT(h != NULL); + DUK_UNREF(thr); + + len = DUK_HBUFFER_GET_SIZE(h); + DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */ + tmp32 = (duk_uint32_t) len; + DUK_RAW_WRITE_U32_BE(p, tmp32); + DUK_MEMCPY((void *) p, + (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h), + len); + p += len; + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_string_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) { + duk_hstring *h_str; + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); + if (tv != NULL && DUK_TVAL_IS_STRING(tv)) { + h_str = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h_str != NULL); + } else { + h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); + DUK_ASSERT(h_str != NULL); + } + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p); + p = duk__dump_hstring_raw(p, h_str); + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_buffer_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) { + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); + if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) { + duk_hbuffer *h_buf; + h_buf = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h_buf != NULL); + DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p); + p = duk__dump_hbuffer_raw(thr, p, h_buf); + } else { + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); + DUK_RAW_WRITE_U32_BE(p, 0); + } + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_uint32_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx, duk_uint32_t def_value) { + duk_tval *tv; + duk_uint32_t val; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); + if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) { + val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv); + } else { + val = def_value; + } + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); + DUK_RAW_WRITE_U32_BE(p, val); + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); + if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *h; + duk_uint_fast32_t i; + + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + + /* We know _Varmap only has own properties so walk property + * table directly. We also know _Varmap is dense and all + * values are numbers; assert for these. GC and finalizers + * shouldn't affect _Varmap so side effects should be fine. + */ + for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { + duk_hstring *key; + duk_tval *tv_val; + duk_uint32_t val; + + key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i); + DUK_ASSERT(key != NULL); /* _Varmap is dense */ + DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)); + tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i); + DUK_ASSERT(tv_val != NULL); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val)); + DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */ + val = DUK_TVAL_GET_FASTINT_U32(tv_val); +#else + val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val); +#endif + + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p); + p = duk__dump_hstring_raw(p, key); + DUK_RAW_WRITE_U32_BE(p, val); + } + } + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); + DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */ + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr)); + if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *h; + duk_uint_fast32_t i; + + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + + /* We know _Formals is dense and all entries will be in the + * array part. GC and finalizers shouldn't affect _Formals + * so side effects should be fine. + */ + for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { + duk_tval *tv_val; + duk_hstring *varname; + + tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i); + DUK_ASSERT(tv_val != NULL); + if (DUK_TVAL_IS_STRING(tv_val)) { + /* Array is dense and contains only strings, but ASIZE may + * be larger than used part and there are UNUSED entries. + */ + varname = DUK_TVAL_GET_STRING(tv_val); + DUK_ASSERT(varname != NULL); + + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p); + p = duk__dump_hstring_raw(p, varname); + } + } + } + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); + DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */ + return p; +} + +static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) { + duk_hthread *thr; + duk_tval *tv, *tv_end; + duk_instr_t *ins, *ins_end; + duk_hobject **fn, **fn_end; + duk_hstring *h_str; + duk_uint32_t count_instr; + duk_uint32_t tmp32; + duk_uint16_t tmp16; + duk_double_t d; + + thr = (duk_hthread *) ctx; + DUK_UNREF(ctx); + DUK_UNREF(thr); + + DUK_DD(DUK_DDPRINT("dumping function %p to %p: " + "consts=[%p,%p[ (%ld bytes, %ld items), " + "funcs=[%p,%p[ (%ld bytes, %ld items), " + "code=[%p,%p[ (%ld bytes, %ld items)", + (void *) func, + (void *) p, + (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func))); + + DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */ + count_instr = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func); + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p); + + /* Fixed header info. */ + tmp32 = count_instr; + DUK_RAW_WRITE_U32_BE(p, tmp32); + tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func); + DUK_RAW_WRITE_U32_BE(p, tmp32); + tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func); + DUK_RAW_WRITE_U32_BE(p, tmp32); + tmp16 = func->nregs; + DUK_RAW_WRITE_U16_BE(p, tmp16); + tmp16 = func->nargs; + DUK_RAW_WRITE_U16_BE(p, tmp16); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + tmp32 = func->start_line; + DUK_RAW_WRITE_U32_BE(p, tmp32); + tmp32 = func->end_line; + DUK_RAW_WRITE_U32_BE(p, tmp32); +#else + DUK_RAW_WRITE_U32_BE(p, 0); + DUK_RAW_WRITE_U32_BE(p, 0); +#endif + tmp32 = ((duk_heaphdr *) func)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK; + DUK_RAW_WRITE_U32_BE(p, tmp32); + + /* Bytecode instructions: endian conversion needed unless + * platform is big endian. + */ + ins = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func); + ins_end = DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func); + DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr); +#if defined(DUK_USE_INTEGER_BE) + DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins)); + p += (size_t) (ins_end - ins); +#else + while (ins != ins_end) { + tmp32 = (duk_uint32_t) (*ins); + DUK_RAW_WRITE_U32_BE(p, tmp32); + ins++; + } +#endif + + /* Constants: variable size encoding. */ + tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func); + tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func); + while (tv != tv_end) { + /* constants are strings or numbers now */ + DUK_ASSERT(DUK_TVAL_IS_STRING(tv) || + DUK_TVAL_IS_NUMBER(tv)); + + if (DUK_TVAL_IS_STRING(tv)) { + h_str = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h_str != NULL); + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p), + *p++ = DUK__SER_STRING; + p = duk__dump_hstring_raw(p, h_str); + } else { + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p); + *p++ = DUK__SER_NUMBER; + d = DUK_TVAL_GET_NUMBER(tv); + DUK_RAW_WRITE_DOUBLE_BE(p, d); + } + tv++; + } + + /* Inner functions recursively. */ + fn = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func); + fn_end = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func); + while (fn != fn_end) { + /* XXX: This causes recursion up to inner function depth + * which is normally not an issue, e.g. mark-and-sweep uses + * a recursion limiter to avoid C stack issues. Avoiding + * this would mean some sort of a work list or just refusing + * to serialize deep functions. + */ + DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn)); + p = duk__dump_func(ctx, (duk_hcompiledfunction *) *fn, bw_ctx, p); + fn++; + } + + /* Object extra properties. + * + * There are some difference between function templates and functions. + * For example, function templates don't have .length and nargs is + * normally used to instantiate the functions. + */ + + p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs); + p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME); + p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME); + p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE); + p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func); + p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func); + + DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p)); + + return p; +} + +/* Load a function from bytecode. The function object returned here must + * match what is created by duk_js_push_closure() with respect to its flags, + * properties, etc. + * + * NOTE: there are intentionally no input buffer length / bound checks. + * Adding them would be easy but wouldn't ensure memory safety as untrusted + * or broken bytecode is unsafe during execution unless the opcodes themselves + * are validated (which is quite complex, especially for indirect opcodes). + */ + +#define DUK__ASSERT_LEFT(n) do { \ + DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \ + } while (0) + +static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) { + duk_hthread *thr; + duk_hcompiledfunction *h_fun; + duk_hbuffer *h_data; + duk_size_t data_size; + duk_uint32_t count_instr, count_const, count_funcs; + duk_uint32_t n; + duk_uint32_t tmp32; + duk_small_uint_t const_type; + duk_uint8_t *fun_data; + duk_uint8_t *q; + duk_idx_t idx_base; + duk_tval *tv1; + duk_uarridx_t arr_idx; + + /* XXX: There's some overlap with duk_js_closure() here, but + * seems difficult to share code. Ensure that the final function + * looks the same as created by duk_js_closure(). + */ + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + + DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end)); + + DUK__ASSERT_LEFT(3 * 4); + count_instr = DUK_RAW_READ_U32_BE(p); + count_const = DUK_RAW_READ_U32_BE(p); + count_funcs = DUK_RAW_READ_U32_BE(p); + + data_size = sizeof(duk_tval) * count_const + + sizeof(duk_hobject *) * count_funcs + + sizeof(duk_instr_t) * count_instr; + + DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld", + (long) count_instr, (long) count_const, + (long) count_const, (long) data_size)); + + /* Value stack is used to ensure reachability of constants and + * inner functions being loaded. Require enough space to handle + * large functions correctly. + */ + duk_require_stack(ctx, 2 + count_const + count_funcs); + idx_base = duk_get_top(ctx); + + /* Push function object, init flags etc. This must match + * duk_js_push_closure() quite carefully. + */ + duk_push_compiledfunction(ctx); + h_fun = duk_get_hcompiledfunction(ctx, -1); + DUK_ASSERT(h_fun != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) h_fun)); + DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun) == NULL); + DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, h_fun) == NULL); + DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, h_fun) == NULL); + + h_fun->nregs = DUK_RAW_READ_U16_BE(p); + h_fun->nargs = DUK_RAW_READ_U16_BE(p); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + h_fun->start_line = DUK_RAW_READ_U32_BE(p); + h_fun->end_line = DUK_RAW_READ_U32_BE(p); +#else + p += 8; /* skip line info */ +#endif + + /* duk_hcompiledfunction flags; quite version specific */ + tmp32 = DUK_RAW_READ_U32_BE(p); + DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); + + /* standard prototype */ + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); + + /* assert just a few critical flags */ + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT); + DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&h_fun->obj)); + DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj)); + + /* Create function 'data' buffer but don't attach it yet. */ + fun_data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, data_size); + DUK_ASSERT(fun_data != NULL); + + /* Load bytecode instructions. */ + DUK_ASSERT(sizeof(duk_instr_t) == 4); + DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t)); +#if defined(DUK_USE_INTEGER_BE) + q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs; + DUK_MEMCPY((void *) q, + (const void *) p, + sizeof(duk_instr_t) * count_instr); + p += sizeof(duk_instr_t) * count_instr; +#else + q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs; + for (n = count_instr; n > 0; n--) { + *((duk_instr_t *) (void *) q) = DUK_RAW_READ_U32_BE(p); + q += sizeof(duk_instr_t); + } +#endif + + /* Load constants onto value stack but don't yet copy to buffer. */ + for (n = count_const; n > 0; n--) { + DUK__ASSERT_LEFT(1); + const_type = DUK_RAW_READ_U8(p); + switch (const_type) { + case DUK__SER_STRING: { + p = duk__load_string_raw(ctx, p); + break; + } + case DUK__SER_NUMBER: { + /* Important to do a fastint check so that constants are + * properly read back as fastints. + */ + duk_tval tv_tmp; + duk_double_t val; + DUK__ASSERT_LEFT(8); + val = DUK_RAW_READ_DOUBLE_BE(p); + DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp, val); + duk_push_tval(ctx, &tv_tmp); + break; + } + default: { + goto format_error; + } + } + } + + /* Load inner functions to value stack, but don't yet copy to buffer. */ + for (n = count_funcs; n > 0; n--) { + p = duk__load_func(ctx, p, p_end); + if (p == NULL) { + goto format_error; + } + } + + /* With constants and inner functions on value stack, we can now + * atomically finish the function 'data' buffer, bump refcounts, + * etc. + * + * Here we take advantage of the value stack being just a duk_tval + * array: we can just memcpy() the constants as long as we incref + * them afterwards. + */ + + h_data = (duk_hbuffer *) duk_get_hbuffer(ctx, idx_base + 1); + DUK_ASSERT(h_data != NULL); + DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data)); + DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_fun, h_data); + DUK_HBUFFER_INCREF(thr, h_data); + + tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */ + DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL); + + q = fun_data; + if (count_const > 0) { + /* Explicit zero size check to avoid NULL 'tv1'. */ + DUK_MEMCPY((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const); + for (n = count_const; n > 0; n--) { + DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */ + q += sizeof(duk_tval); + } + tv1 += count_const; + } + + DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q); + for (n = count_funcs; n > 0; n--) { + duk_hobject *h_obj; + + DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1)); + h_obj = DUK_TVAL_GET_OBJECT(tv1); + DUK_ASSERT(h_obj != NULL); + tv1++; + DUK_HOBJECT_INCREF(thr, h_obj); + + *((duk_hobject **) (void *) q) = h_obj; + q += sizeof(duk_hobject *); + } + + DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q); + + /* The function object is now reachable and refcounts are fine, + * so we can pop off all the temporaries. + */ + DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx, idx_base))); + duk_set_top(ctx, idx_base + 1); + + /* Setup function properties. */ + tmp32 = DUK_RAW_READ_U32_BE(p); + duk_push_u32(ctx, tmp32); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); + + p = duk__load_string_raw(ctx, p); + if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) { + /* Original function instance/template had NAMEBINDING. + * Must create a lexical environment on loading to allow + * recursive functions like 'function foo() { foo(); }'. + */ + duk_hobject *proto; + + proto = thr->builtins[DUK_BIDX_GLOBAL_ENV]; + (void) duk_push_object_helper_proto(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), + proto); + duk_dup(ctx, -2); /* -> [ func funcname env funcname ] */ + duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */ + duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */ + duk_xdef_prop_stridx(ctx, idx_base, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC); + /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it + * will be ignored anyway + */ + } + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); + + p = duk__load_string_raw(ctx, p); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC); + + duk_push_object(ctx); + duk_dup(ctx, -2); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */ + duk_compact(ctx, -1); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); + + p = duk__load_buffer_raw(ctx, p); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC); + + duk_push_object(ctx); /* _Varmap */ + for (;;) { + /* XXX: awkward */ + p = duk__load_string_raw(ctx, p); + if (duk_get_length(ctx, -1) == 0) { + duk_pop(ctx); + break; + } + tmp32 = DUK_RAW_READ_U32_BE(p); + duk_push_u32(ctx, tmp32); + duk_put_prop(ctx, -3); + } + duk_compact(ctx, -1); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); + + duk_push_array(ctx); /* _Formals */ + for (arr_idx = 0; ; arr_idx++) { + /* XXX: awkward */ + p = duk__load_string_raw(ctx, p); + if (duk_get_length(ctx, -1) == 0) { + duk_pop(ctx); + break; + } + duk_put_prop_index(ctx, -2, arr_idx); + } + duk_compact(ctx, -1); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); + + /* Return with final function pushed on stack top. */ + DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1))); + DUK_ASSERT_TOP(ctx, idx_base + 1); + return p; + + format_error: + return NULL; +} + +DUK_EXTERNAL void duk_dump_function(duk_context *ctx) { + duk_hthread *thr; + duk_hcompiledfunction *func; + duk_bufwriter_ctx bw_ctx_alloc; + duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc; + duk_uint8_t *p; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + + /* Bound functions don't have all properties so we'd either need to + * lookup the non-bound target function or reject bound functions. + * For now, bound functions are rejected. + */ + func = duk_require_hcompiledfunction(ctx, -1); + DUK_ASSERT(func != NULL); + DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func->obj)); + + /* Estimating the result size beforehand would be costly, so + * start with a reasonable size and extend as needed. + */ + DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC); + p = DUK_BW_GET_PTR(thr, bw_ctx); + *p++ = DUK__SER_MARKER; + *p++ = DUK__SER_VERSION; + p = duk__dump_func(ctx, func, bw_ctx, p); + DUK_BW_SET_PTR(thr, bw_ctx, p); + DUK_BW_COMPACT(thr, bw_ctx); + + DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1))); + + duk_remove(ctx, -2); /* [ ... func buf ] -> [ ... buf ] */ +} + +DUK_EXTERNAL void duk_load_function(duk_context *ctx) { + duk_hthread *thr; + duk_uint8_t *p_buf, *p, *p_end; + duk_size_t sz; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + DUK_UNREF(ctx); + + p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz); + DUK_ASSERT(p_buf != NULL); + + /* The caller is responsible for being sure that bytecode being loaded + * is valid and trusted. Invalid bytecode can cause memory unsafe + * behavior directly during loading or later during bytecode execution + * (instruction validation would be quite complex to implement). + * + * This signature check is the only sanity check for detecting + * accidental invalid inputs. The initial 0xFF byte ensures no + * ordinary string will be accepted by accident. + */ + p = p_buf; + p_end = p_buf + sz; + if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) { + goto format_error; + } + p += 2; + + p = duk__load_func(ctx, p, p_end); + if (p == NULL) { + goto format_error; + } + + duk_remove(ctx, -2); /* [ ... buf func ] -> [ ... func ] */ + return; + + format_error: + DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED); +} + +#undef DUK__SER_MARKER +#undef DUK__SER_VERSION +#undef DUK__SER_STRING +#undef DUK__SER_NUMBER +#undef DUK__BYTECODE_INITIAL_ALLOC + +#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */ + +DUK_EXTERNAL void duk_dump_function(duk_context *ctx) { + DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx); +} + +DUK_EXTERNAL void duk_load_function(duk_context *ctx) { + DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx); +} + +#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */ +/* + * Calls. + * + * Protected variants should avoid ever throwing an error. + */ + +/* include removed: duk_internal.h */ + +/* Prepare value stack for a method call through an object property. + * May currently throw an error e.g. when getting the property. + */ +DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_index, duk_idx_t nargs) { + DUK_ASSERT_CTX_VALID(ctx); + + DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_index=%ld, nargs=%ld, stacktop=%ld", + (long) normalized_obj_index, (long) nargs, (long) duk_get_top(ctx))); + + /* [... key arg1 ... argN] */ + + /* duplicate key */ + duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */ + duk_get_prop(ctx, normalized_obj_index); + + DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1))); + + /* [... key arg1 ... argN func] */ + + duk_replace(ctx, -nargs - 2); + + /* [... func arg1 ... argN] */ + + duk_dup(ctx, normalized_obj_index); + duk_insert(ctx, -nargs - 1); + + /* [... func this arg1 ... argN] */ +} + +DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_small_uint_t call_flags; + duk_idx_t idx_func; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + idx_func = duk_get_top(ctx) - nargs - 1; + if (idx_func < 0 || nargs < 0) { + /* note that we can't reliably pop anything here */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + } + + /* XXX: awkward; we assume there is space for this, overwrite + * directly instead? + */ + duk_push_undefined(ctx); + duk_insert(ctx, idx_func + 1); + + call_flags = 0; /* not protected, respect reclimit, not constructor */ + + duk_handle_call_unprotected(thr, /* thread */ + nargs, /* num_stack_args */ + call_flags); /* call_flags */ +} + +DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_small_uint_t call_flags; + duk_idx_t idx_func; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ + if (idx_func < 0 || nargs < 0) { + /* note that we can't reliably pop anything here */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + } + + call_flags = 0; /* not protected, respect reclimit, not constructor */ + + duk_handle_call_unprotected(thr, /* thread */ + nargs, /* num_stack_args */ + call_flags); /* call_flags */ +} + +DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) { + /* + * XXX: if duk_handle_call() took values through indices, this could be + * made much more sensible. However, duk_handle_call() needs to fudge + * the 'this' and 'func' values to handle bound function chains, which + * is now done "in-place", so this is not a trivial change. + */ + + DUK_ASSERT_CTX_VALID(ctx); + + obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */ + + duk__call_prop_prep_stack(ctx, obj_index, nargs); + + duk_call_method(ctx, nargs); +} + +DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_small_uint_t call_flags; + duk_idx_t idx_func; + duk_int_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */ + if (idx_func < 0 || nargs < 0) { + /* We can't reliably pop anything here because the stack input + * shape is incorrect. So we throw an error; if the caller has + * no catch point for this, a fatal error will occur. Another + * alternative would be to just return an error. But then the + * stack would be in an unknown state which might cause some + * very hard to diagnose problems later on. Also note that even + * if we did not throw an error here, the underlying call handler + * might STILL throw an out-of-memory error or some other internal + * fatal error. + */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + return DUK_EXEC_ERROR; /* unreachable */ + } + + /* awkward; we assume there is space for this */ + duk_push_undefined(ctx); + duk_insert(ctx, idx_func + 1); + + call_flags = 0; /* respect reclimit, not constructor */ + + rc = duk_handle_call_protected(thr, /* thread */ + nargs, /* num_stack_args */ + call_flags); /* call_flags */ + + return rc; +} + +DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_small_uint_t call_flags; + duk_idx_t idx_func; + duk_int_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ + if (idx_func < 0 || nargs < 0) { + /* See comments in duk_pcall(). */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + return DUK_EXEC_ERROR; /* unreachable */ + } + + call_flags = 0; /* respect reclimit, not constructor */ + + rc = duk_handle_call_protected(thr, /* thread */ + nargs, /* num_stack_args */ + call_flags); /* call_flags */ + + return rc; +} + +DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx) { + duk_idx_t obj_index; + duk_idx_t nargs; + + /* Get the original arguments. Note that obj_index may be a relative + * index so the stack must have the same top when we use it. + */ + + DUK_ASSERT_CTX_VALID(ctx); + + obj_index = (duk_idx_t) duk_get_int(ctx, -2); + nargs = (duk_idx_t) duk_get_int(ctx, -1); + duk_pop_2(ctx); + + obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */ + duk__call_prop_prep_stack(ctx, obj_index, nargs); + duk_call_method(ctx, nargs); + return 1; +} + +DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) { + /* + * Must be careful to catch errors related to value stack manipulation + * and property lookup, not just the call itself. + */ + + DUK_ASSERT_CTX_VALID(ctx); + + duk_push_idx(ctx, obj_index); + duk_push_idx(ctx, nargs); + + /* Inputs: explicit arguments (nargs), +1 for key, +2 for obj_index/nargs passing. + * If the value stack does not contain enough args, an error is thrown; this matches + * behavior of the other protected call API functions. + */ + return duk_safe_call(ctx, duk__pcall_prop_raw, nargs + 1 + 2 /*nargs*/, 1 /*nrets*/); +} + +DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_int_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + if (duk_get_top(ctx) < nargs || nrets < 0) { + /* See comments in duk_pcall(). */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + return DUK_EXEC_ERROR; /* unreachable */ + } + + rc = duk_handle_safe_call(thr, /* thread */ + func, /* func */ + nargs, /* num_stack_args */ + nrets); /* num_stack_res */ + + return rc; +} + +DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) { + /* + * There are two [[Construct]] operations in the specification: + * + * - E5 Section 13.2.2: for Function objects + * - E5 Section 15.3.4.5.2: for "bound" Function objects + * + * The chain of bound functions is resolved in Section 15.3.4.5.2, + * with arguments "piling up" until the [[Construct]] internal + * method is called on the final, actual Function object. Note + * that the "prototype" property is looked up *only* from the + * final object, *before* calling the constructor. + * + * Currently we follow the bound function chain here to get the + * "prototype" property value from the final, non-bound function. + * However, we let duk_handle_call() handle the argument "piling" + * when the constructor is called. The bound function chain is + * thus now processed twice. + * + * When constructing new Array instances, an unnecessary object is + * created and discarded now: the standard [[Construct]] creates an + * object, and calls the Array constructor. The Array constructor + * returns an Array instance, which is used as the result value for + * the "new" operation; the object created before the Array constructor + * call is discarded. + * + * This would be easy to fix, e.g. by knowing that the Array constructor + * will always create a replacement object and skip creating the fallback + * object in that case. + * + * Note: functions called via "new" need to know they are called as a + * constructor. For instance, built-in constructors behave differently + * depending on how they are called. + */ + + /* XXX: merge this with duk_js_call.c, as this function implements + * core semantics (or perhaps merge the two files altogether). + */ + + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *proto; + duk_hobject *cons; + duk_hobject *fallback; + duk_idx_t idx_cons; + duk_small_uint_t call_flags; + + DUK_ASSERT_CTX_VALID(ctx); + + /* [... constructor arg1 ... argN] */ + + idx_cons = duk_require_normalize_index(ctx, -nargs - 1); + + DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld", + (long) duk_get_top(ctx), (long) nargs, (long) idx_cons)); + + /* XXX: code duplication */ + + /* + * Figure out the final, non-bound constructor, to get "prototype" + * property. + */ + + duk_dup(ctx, idx_cons); + for (;;) { + duk_tval *tv; + tv = DUK_GET_TVAL_NEGIDX(ctx, -1); + DUK_ASSERT(tv != NULL); + + if (DUK_TVAL_IS_OBJECT(tv)) { + cons = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(cons != NULL); + if (!DUK_HOBJECT_IS_CALLABLE(cons) || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) { + /* Checking callability of the immediate target + * is important, same for constructability. + * Checking it for functions down the bound + * function chain is not strictly necessary + * because .bind() should normally reject them. + * But it's good to check anyway because it's + * technically possible to edit the bound function + * chain via internal keys. + */ + goto not_constructable; + } + if (!DUK_HOBJECT_HAS_BOUND(cons)) { + break; + } + } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { + /* Lightfuncs cannot be bound. */ + break; + } else { + /* Anything else is not constructable. */ + goto not_constructable; + } + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */ + duk_remove(ctx, -2); /* -> [... target] */ + } + DUK_ASSERT(duk_is_callable(ctx, -1)); + DUK_ASSERT(duk_is_lightfunc(ctx, -1) || + (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUND(duk_get_hobject(ctx, -1)))); + + /* [... constructor arg1 ... argN final_cons] */ + + /* + * Create "fallback" object to be used as the object instance, + * unless the constructor returns a replacement value. + * Its internal prototype needs to be set based on "prototype" + * property of the constructor. + */ + + duk_push_object(ctx); /* class Object, extensible */ + + /* [... constructor arg1 ... argN final_cons fallback] */ + + duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE); + proto = duk_get_hobject(ctx, -1); + if (!proto) { + DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object " + "-> leave standard Object prototype as fallback prototype")); + } else { + DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value " + "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto)); + fallback = duk_get_hobject(ctx, -2); + DUK_ASSERT(fallback != NULL); + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto); + } + duk_pop(ctx); + + /* [... constructor arg1 ... argN final_cons fallback] */ + + /* + * Manipulate callstack for the call. + */ + + duk_dup_top(ctx); + duk_insert(ctx, idx_cons + 1); /* use fallback as 'this' value */ + duk_insert(ctx, idx_cons); /* also stash it before constructor, + * in case we need it (as the fallback value) + */ + duk_pop(ctx); /* pop final_cons */ + + + /* [... fallback constructor fallback(this) arg1 ... argN]; + * Note: idx_cons points to first 'fallback', not 'constructor'. + */ + + DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, " + "nargs=%ld, top=%ld", + (duk_tval *) duk_get_tval(ctx, idx_cons + 1), + (duk_tval *) duk_get_tval(ctx, idx_cons + 2), + (long) nargs, + (long) duk_get_top(ctx))); + + /* + * Call the constructor function (called in "constructor mode"). + */ + + call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */ + + duk_handle_call_unprotected(thr, /* thread */ + nargs, /* num_stack_args */ + call_flags); /* call_flags */ + + /* [... fallback retval] */ + + DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT", + (duk_tval *) duk_get_tval(ctx, -2), + (duk_tval *) duk_get_tval(ctx, -1))); + + /* + * Determine whether to use the constructor return value as the created + * object instance or not. + */ + + if (duk_is_object(ctx, -1)) { + duk_remove(ctx, -2); + } else { + duk_pop(ctx); + } + + /* + * Augment created errors upon creation (not when they are thrown or + * rethrown). __FILE__ and __LINE__ are not desirable here; the call + * stack reflects the caller which is correct. + */ + +#ifdef DUK_USE_AUGMENT_ERROR_CREATE + duk_hthread_sync_currpc(thr); + duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/); +#endif + + /* [... retval] */ + + return; + + not_constructable: + DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE); +} + +DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx) { + duk_uint_t nargs; + + nargs = duk_to_uint(ctx, -1); + duk_pop(ctx); + + duk_new(ctx, nargs); + return 1; +} + +DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) { + duk_int_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + + /* For now, just use duk_safe_call() to wrap duk_new(). We can't + * simply use a protected duk_handle_call() because there's post + * processing which might throw. It should be possible to ensure + * the post processing never throws (except in internal errors and + * out of memory etc which are always allowed) and then remove this + * wrapper. + */ + + duk_push_uint(ctx, nargs); + rc = duk_safe_call(ctx, duk__pnew_helper, nargs + 2 /*nargs*/, 1 /*nrets*/); + return rc; +} + +DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); + + act = duk_hthread_get_current_activation(thr); + DUK_ASSERT(act != NULL); /* because callstack_top > 0 */ + return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); +} + +DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + + /* For user code this could just return 1 (strict) always + * because all Duktape/C functions are considered strict, + * and strict is also the default when nothing is running. + * However, Duktape may call this function internally when + * the current activation is an Ecmascript function, so + * this cannot be replaced by a 'return 1' without fixing + * the internal call sites. + */ + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); + + act = duk_hthread_get_current_activation(thr); + if (act == NULL) { + /* Strict by default. */ + return 1; + } + return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); +} + +/* + * Duktape/C function magic + */ + +DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + duk_hobject *func; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); + + act = duk_hthread_get_current_activation(thr); + if (act) { + func = DUK_ACT_GET_FUNC(act); + if (!func) { + duk_tval *tv = &act->tv_func; + duk_small_uint_t lf_flags; + lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); + return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); + } + DUK_ASSERT(func != NULL); + + if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) { + duk_hnativefunction *nf = (duk_hnativefunction *) func; + return (duk_int_t) nf->magic; + } + } + return 0; +} + +DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_hobject *h; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + if (DUK_TVAL_IS_OBJECT(tv)) { + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + if (!DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) { + goto type_error; + } + return (duk_int_t) ((duk_hnativefunction *) h)->magic; + } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { + duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); + return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); + } + + /* fall through */ + type_error: + DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); + return 0; +} + +DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic) { + duk_hnativefunction *nf; + + DUK_ASSERT_CTX_VALID(ctx); + + nf = duk_require_hnativefunction(ctx, index); + DUK_ASSERT(nf != NULL); + nf->magic = (duk_int16_t) magic; +} +/* + * Encoding and decoding basic formats: hex, base64. + * + * These are in-place operations which may allow an optimized implementation. + * + * Base-64: https://tools.ietf.org/html/rfc4648#section-4 + */ + +/* include removed: duk_internal.h */ + +/* Shared handling for encode/decode argument. Fast path handling for + * buffer and string values because they're the most common. In particular, + * avoid creating a temporary string or buffer when possible. + */ +DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { + DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */ + if (duk_is_buffer(ctx, index)) { + return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len); + } else { + return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len); + } +} + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { + duk_uint_t t; + duk_size_t n_full, n_full3, n_final; + const duk_uint8_t *src_end_fast; + + n_full = srclen / 3; /* full 3-byte -> 4-char conversions */ + n_full3 = n_full * 3; + n_final = srclen - n_full3; + DUK_ASSERT_DISABLE(n_final >= 0); + DUK_ASSERT(n_final <= 2); + + src_end_fast = src + n_full3; + while (DUK_UNLIKELY(src != src_end_fast)) { + t = (duk_uint_t) (*src++); + t = (t << 8) + (duk_uint_t) (*src++); + t = (t << 8) + (duk_uint_t) (*src++); + + *dst++ = duk_base64_enctab[t >> 18]; + *dst++ = duk_base64_enctab[(t >> 12) & 0x3f]; + *dst++ = duk_base64_enctab[(t >> 6) & 0x3f]; + *dst++ = duk_base64_enctab[t & 0x3f]; + +#if 0 /* Tested: not faster on x64 */ + /* aaaaaabb bbbbcccc ccdddddd */ + dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f]; + dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)]; + dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)]; + dst[3] = duk_base64_enctab[src[2] & 0x3f]; + src += 3; dst += 4; +#endif + } + + switch (n_final) { + /* case 0: nop */ + case 1: { + /* XX== */ + t = (duk_uint_t) (*src++); + *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */ + *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */ + *dst++ = DUK_ASC_EQUALS; + *dst++ = DUK_ASC_EQUALS; + break; + } + case 2: { + /* XXX= */ + t = (duk_uint_t) (*src++); + t = (t << 8) + (duk_uint_t) (*src++); + *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */ + *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */ + *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */ + *dst++ = DUK_ASC_EQUALS; + break; + } + } +} +#else /* DUK_USE_BASE64_FASTPATH */ +DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { + duk_small_uint_t i, snip; + duk_uint_t t; + duk_uint_fast8_t x, y; + const duk_uint8_t *src_end; + + src_end = src + srclen; + + while (src < src_end) { + /* read 3 bytes into 't', padded by zero */ + snip = 4; + t = 0; + for (i = 0; i < 3; i++) { + t = t << 8; + if (src >= src_end) { + snip--; + } else { + t += (duk_uint_t) (*src++); + } + } + + /* + * Missing bytes snip base64 example + * 0 4 XXXX + * 1 3 XXX= + * 2 2 XX== + */ + + DUK_ASSERT(snip >= 2 && snip <= 4); + + for (i = 0; i < 4; i++) { + x = (duk_uint_fast8_t) ((t >> 18) & 0x3f); + t = t << 6; + + /* A straightforward 64-byte lookup would be faster + * and cleaner, but this is shorter. + */ + if (i >= snip) { + y = '='; + } else if (x <= 25) { + y = x + 'A'; + } else if (x <= 51) { + y = x - 26 + 'a'; + } else if (x <= 61) { + y = x - 52 + '0'; + } else if (x == 62) { + y = '+'; + } else { + y = '/'; + } + + *dst++ = (duk_uint8_t) y; + } + } +} +#endif /* DUK_USE_BASE64_FASTPATH */ + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { + duk_int_t x; + duk_int_t t; + duk_small_uint_t n_equal; + duk_small_uint_t n_chars; + const duk_uint8_t *src_end; + const duk_uint8_t *src_end_safe; + + src_end = src + srclen; + src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */ + + /* Innermost fast path processes 4 valid base-64 characters at a time + * but bails out on whitespace, padding chars ('=') and invalid chars. + * Once the slow path segment has been processed, we return to the + * inner fast path again. This handles e.g. base64 with newlines + * reasonably well because the majority of a line is in the fast path. + */ + for (;;) { + /* Fast path, handle units with just actual encoding characters. */ + + while (src <= src_end_safe) { + /* The lookup byte is intentionally sign extended to (at least) + * 32 bits and then ORed. This ensures that is at least 1 byte + * is negative, the highest bit of 't' will be set at the end + * and we don't need to check every byte. + */ + DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p", + (const void *) src, (const void *) src_end_safe, (const void *) src_end)); + + t = (duk_int_t) duk_base64_dectab[*src++]; + t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + + if (DUK_UNLIKELY(t < 0)) { + DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit")); + src -= 4; + break; + } + + DUK_ASSERT(t <= 0xffffffL); + DUK_ASSERT((t >> 24) == 0); + *dst++ = (duk_uint8_t) (t >> 16); + *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); + *dst++ = (duk_uint8_t) (t & 0xff); + } + + /* Handle one slow path unit (or finish if we're done). */ + + n_equal = 0; + n_chars = 0; + t = 0; + for (;;) { + DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld", + (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t)); + + if (DUK_UNLIKELY(src >= src_end)) { + goto done; /* two level break */ + } + + x = duk_base64_dectab[*src++]; + if (DUK_UNLIKELY(x < 0)) { + if (x == -2) { + continue; /* allowed ascii whitespace */ + } else if (x == -3) { + n_equal++; + t <<= 6; + } else { + DUK_ASSERT(x == -1); + goto error; + } + } else { + DUK_ASSERT(x >= 0 && x <= 63); + if (n_equal > 0) { + /* Don't allow actual chars after equal sign. */ + goto error; + } + t = (t << 6) + x; + } + + if (DUK_UNLIKELY(n_chars == 3)) { + /* Emit 3 bytes and backtrack if there was padding. There's + * always space for the whole 3 bytes so no check needed. + */ + DUK_ASSERT(t <= 0xffffffL); + DUK_ASSERT((t >> 24) == 0); + *dst++ = (duk_uint8_t) (t >> 16); + *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); + *dst++ = (duk_uint8_t) (t & 0xff); + + if (DUK_UNLIKELY(n_equal > 0)) { + DUK_ASSERT(n_equal <= 4); + + /* There may be whitespace between the equal signs. */ + if (n_equal == 1) { + /* XXX= */ + dst -= 1; + } else if (n_equal == 2) { + /* XX== */ + dst -= 2; + } else { + goto error; /* invalid padding */ + } + + /* Continue parsing after padding, allows concatenated, + * padded base64. + */ + } + break; /* back to fast loop */ + } else { + n_chars++; + } + } + } + done: + DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld", + (const void *) src, (const void *) src_end, (long) n_chars)); + + DUK_ASSERT(src == src_end); + + if (n_chars != 0) { + /* Here we'd have the option of decoding unpadded base64 + * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not + * accepted. + */ + goto error; + } + + *out_dst_final = dst; + return 1; + + error: + return 0; +} +#else /* DUK_USE_BASE64_FASTPATH */ +DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { + duk_uint_t t; + duk_uint_fast8_t x, y; + duk_small_uint_t group_idx; + duk_small_uint_t n_equal; + const duk_uint8_t *src_end; + + src_end = src + srclen; + t = 0; + group_idx = 0; + n_equal = 0; + + while (src < src_end) { + x = *src++; + + if (x >= 'A' && x <= 'Z') { + y = x - 'A' + 0; + } else if (x >= 'a' && x <= 'z') { + y = x - 'a' + 26; + } else if (x >= '0' && x <= '9') { + y = x - '0' + 52; + } else if (x == '+') { + y = 62; + } else if (x == '/') { + y = 63; + } else if (x == '=') { + /* We don't check the zero padding bytes here right now + * (that they're actually zero). This seems to be common + * behavior for base-64 decoders. + */ + + n_equal++; + t <<= 6; /* shift in zeroes */ + goto skip_add; + } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) { + /* allow basic ASCII whitespace */ + continue; + } else { + goto error; + } + + if (n_equal > 0) { + /* Don't allow mixed padding and actual chars. */ + goto error; + } + t = (t << 6) + y; + skip_add: + + if (group_idx == 3) { + /* output 3 bytes from 't' */ + *dst++ = (duk_uint8_t) ((t >> 16) & 0xff); + *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); + *dst++ = (duk_uint8_t) (t & 0xff); + + if (DUK_UNLIKELY(n_equal > 0)) { + /* Backtrack. */ + DUK_ASSERT(n_equal <= 4); + if (n_equal == 1) { + dst -= 1; + } else if (n_equal == 2) { + dst -= 2; + } else { + goto error; /* invalid padding */ + } + + /* Here we can choose either to end parsing and ignore + * whatever follows, or to continue parsing in case + * multiple (possibly padded) base64 strings have been + * concatenated. Currently, keep on parsing. + */ + n_equal = 0; + } + + t = 0; + group_idx = 0; + } else { + group_idx++; + } + } + + if (group_idx != 0) { + /* Here we'd have the option of decoding unpadded base64 + * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not + * accepted. + */ + goto error; + } + + *out_dst_final = dst; + return 1; + + error: + return 0; +} +#endif /* DUK_USE_BASE64_FASTPATH */ + +DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + const duk_uint8_t *src; + duk_size_t srclen; + duk_size_t dstlen; + duk_uint8_t *dst; + const char *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + /* XXX: optimize for string inputs: no need to coerce to a buffer + * which makes a copy of the input. + */ + + index = duk_require_normalize_index(ctx, index); + src = duk__prep_codec_arg(ctx, index, &srclen); + /* Note: for srclen=0, src may be NULL */ + + /* Computation must not wrap; this limit works for 32-bit size_t: + * >>> srclen = 3221225469 + * >>> '%x' % ((srclen + 2) / 3 * 4) + * 'fffffffc' + */ + if (srclen > 3221225469UL) { + goto type_error; + } + dstlen = (srclen + 2) / 3 * 4; + dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen); + + duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst); + + ret = duk_to_string(ctx, -1); + duk_replace(ctx, index); + return ret; + + type_error: + DUK_ERROR_TYPE(thr, DUK_STR_ENCODE_FAILED); + return NULL; /* never here */ +} + +DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + const duk_uint8_t *src; + duk_size_t srclen; + duk_size_t dstlen; + duk_uint8_t *dst; + duk_uint8_t *dst_final; + duk_bool_t retval; + + DUK_ASSERT_CTX_VALID(ctx); + + /* XXX: optimize for buffer inputs: no need to coerce to a string + * which causes an unnecessary interning. + */ + + index = duk_require_normalize_index(ctx, index); + src = duk__prep_codec_arg(ctx, index, &srclen); + + /* Computation must not wrap, only srclen + 3 is at risk of + * wrapping because after that the number gets smaller. + * This limit works for 32-bit size_t: + * 0x100000000 - 3 - 1 = 4294967292 + */ + if (srclen > 4294967292UL) { + goto type_error; + } + dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */ + dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen); + /* Note: for dstlen=0, dst may be NULL */ + + retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final); + if (!retval) { + goto type_error; + } + + /* XXX: convert to fixed buffer? */ + (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst)); + duk_replace(ctx, index); + return; + + type_error: + DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED); +} + +DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) { + const duk_uint8_t *inp; + duk_size_t len; + duk_size_t i; + duk_uint8_t *buf; + const char *ret; +#if defined(DUK_USE_HEX_FASTPATH) + duk_size_t len_safe; + duk_uint16_t *p16; +#endif + + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_require_normalize_index(ctx, index); + inp = duk__prep_codec_arg(ctx, index, &len); + DUK_ASSERT(inp != NULL || len == 0); + + /* Fixed buffer, no zeroing because we'll fill all the data. */ + buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/); + DUK_ASSERT(buf != NULL); + +#if defined(DUK_USE_HEX_FASTPATH) + DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */ + p16 = (duk_uint16_t *) (void *) buf; + len_safe = len & ~0x03U; + for (i = 0; i < len_safe; i += 4) { + p16[0] = duk_hex_enctab[inp[i]]; + p16[1] = duk_hex_enctab[inp[i + 1]]; + p16[2] = duk_hex_enctab[inp[i + 2]]; + p16[3] = duk_hex_enctab[inp[i + 3]]; + p16 += 4; + } + for (; i < len; i++) { + *p16++ = duk_hex_enctab[inp[i]]; + } +#else /* DUK_USE_HEX_FASTPATH */ + for (i = 0; i < len; i++) { + duk_small_uint_t t; + t = (duk_small_uint_t) inp[i]; + buf[i*2 + 0] = duk_lc_digits[t >> 4]; + buf[i*2 + 1] = duk_lc_digits[t & 0x0f]; + } +#endif /* DUK_USE_HEX_FASTPATH */ + + /* XXX: Using a string return value forces a string intern which is + * not always necessary. As a rough performance measure, hex encode + * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s + * without string coercion. Change to returning a buffer and let the + * caller coerce to string if necessary? + */ + + ret = duk_to_string(ctx, -1); + duk_replace(ctx, index); + return ret; +} + +DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + const duk_uint8_t *inp; + duk_size_t len; + duk_size_t i; + duk_int_t t; + duk_uint8_t *buf; +#if defined(DUK_USE_HEX_FASTPATH) + duk_int_t chk; + duk_uint8_t *p; + duk_size_t len_safe; +#endif + + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_require_normalize_index(ctx, index); + inp = duk__prep_codec_arg(ctx, index, &len); + DUK_ASSERT(inp != NULL || len == 0); + + if (len & 0x01) { + goto type_error; + } + + /* Fixed buffer, no zeroing because we'll fill all the data. */ + buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/); + DUK_ASSERT(buf != NULL); + +#if defined(DUK_USE_HEX_FASTPATH) + p = buf; + len_safe = len & ~0x07U; + for (i = 0; i < len_safe; i += 8) { + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + chk = t; + p[0] = (duk_uint8_t) t; + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 3]]); + chk |= t; + p[1] = (duk_uint8_t) t; + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 5]]); + chk |= t; + p[2] = (duk_uint8_t) t; + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 7]]); + chk |= t; + p[3] = (duk_uint8_t) t; + p += 4; + + /* Check if any lookup above had a negative result. */ + if (DUK_UNLIKELY(chk < 0)) { + goto type_error; + } + } + for (; i < len; i += 2) { + t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | + ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + if (DUK_UNLIKELY(t < 0)) { + goto type_error; + } + *p++ = (duk_uint8_t) t; + } +#else /* DUK_USE_HEX_FASTPATH */ + for (i = 0; i < len; i += 2) { + /* For invalid characters the value -1 gets extended to + * at least 16 bits. If either nybble is invalid, the + * resulting 't' will be < 0. + */ + t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | + ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + if (DUK_UNLIKELY(t < 0)) { + goto type_error; + } + buf[i >> 1] = (duk_uint8_t) t; + } +#endif /* DUK_USE_HEX_FASTPATH */ + + duk_replace(ctx, index); + return; + + type_error: + DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED); +} + +DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t index) { +#ifdef DUK_USE_ASSERTIONS + duk_idx_t top_at_entry; +#endif + const char *ret; + + DUK_ASSERT_CTX_VALID(ctx); +#ifdef DUK_USE_ASSERTIONS + top_at_entry = duk_get_top(ctx); +#endif + + index = duk_require_normalize_index(ctx, index); + duk_bi_json_stringify_helper(ctx, + index /*idx_value*/, + DUK_INVALID_INDEX /*idx_replacer*/, + DUK_INVALID_INDEX /*idx_space*/, + 0 /*flags*/); + DUK_ASSERT(duk_is_string(ctx, -1)); + duk_replace(ctx, index); + ret = duk_get_string(ctx, index); + + DUK_ASSERT(duk_get_top(ctx) == top_at_entry); + + return ret; +} + +DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t index) { +#ifdef DUK_USE_ASSERTIONS + duk_idx_t top_at_entry; +#endif + + DUK_ASSERT_CTX_VALID(ctx); +#ifdef DUK_USE_ASSERTIONS + top_at_entry = duk_get_top(ctx); +#endif + + index = duk_require_normalize_index(ctx, index); + duk_bi_json_parse_helper(ctx, + index /*idx_value*/, + DUK_INVALID_INDEX /*idx_reviver*/, + 0 /*flags*/); + duk_replace(ctx, index); + + DUK_ASSERT(duk_get_top(ctx) == top_at_entry); +} +/* + * Compilation and evaluation + */ + +/* include removed: duk_internal.h */ + +typedef struct duk__compile_raw_args duk__compile_raw_args; +struct duk__compile_raw_args { + duk_size_t src_length; /* should be first on 64-bit platforms */ + const duk_uint8_t *src_buffer; + duk_uint_t flags; +}; + +/* Eval is just a wrapper now. */ +DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { + duk_uint_t comp_flags; + duk_int_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + + /* Note: strictness is *not* inherited from the current Duktape/C. + * This would be confusing because the current strictness state + * depends on whether we're running inside a Duktape/C activation + * (= strict mode) or outside of any activation (= non-strict mode). + * See tests/api/test-eval-strictness.c for more discussion. + */ + + /* [ ... source? filename? ] (depends on flags) */ + + comp_flags = flags; + comp_flags |= DUK_COMPILE_EVAL; + rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */ + + /* [ ... closure/error ] */ + + if (rc != DUK_EXEC_SUCCESS) { + rc = DUK_EXEC_ERROR; + goto got_rc; + } + + duk_push_global_object(ctx); /* explicit 'this' binding, see GH-164 */ + + if (flags & DUK_COMPILE_SAFE) { + rc = duk_pcall_method(ctx, 0); + } else { + duk_call_method(ctx, 0); + rc = DUK_EXEC_SUCCESS; + } + + /* [ ... result/error ] */ + + got_rc: + if (flags & DUK_COMPILE_NORESULT) { + duk_pop(ctx); + } + + return rc; +} + +/* Helper which can be called both directly and with duk_safe_call(). */ +DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk__compile_raw_args *comp_args; + duk_uint_t flags; + duk_small_uint_t comp_flags; + duk_hcompiledfunction *h_templ; + + DUK_ASSERT_CTX_VALID(ctx); + + /* Note: strictness is not inherited from the current Duktape/C + * context. Otherwise it would not be possible to compile + * non-strict code inside a Duktape/C activation (which is + * always strict now). See tests/api/test-eval-strictness.c + * for discussion. + */ + + /* [ ... source? filename? &comp_args ] (depends on flags) */ + + comp_args = (duk__compile_raw_args *) duk_require_pointer(ctx, -1); + flags = comp_args->flags; + duk_pop(ctx); + + /* [ ... source? filename? ] */ + + if (flags & DUK_COMPILE_NOFILENAME) { + /* Automatic filename: 'eval' or 'input'. */ + duk_push_hstring_stridx(ctx, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT); + } + + /* [ ... source? filename ] */ + + if (!comp_args->src_buffer) { + duk_hstring *h_sourcecode; + + h_sourcecode = duk_get_hstring(ctx, -2); + if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */ + (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */ + /* XXX: when this error is caused by a nonexistent + * file given to duk_peval_file() or similar, the + * error message is not the best possible. + */ + DUK_ERROR_API(thr, DUK_STR_NO_SOURCECODE); + } + DUK_ASSERT(h_sourcecode != NULL); + comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode); + comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode); + } + DUK_ASSERT(comp_args->src_buffer != NULL); + + /* XXX: unnecessary translation of flags */ + comp_flags = 0; + if (flags & DUK_COMPILE_EVAL) { + comp_flags |= DUK_JS_COMPILE_FLAG_EVAL; + } + if (flags & DUK_COMPILE_FUNCTION) { + comp_flags |= DUK_JS_COMPILE_FLAG_EVAL | + DUK_JS_COMPILE_FLAG_FUNCEXPR; + } + if (flags & DUK_COMPILE_STRICT) { + comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + } + + /* [ ... source? filename ] */ + + duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags); + + /* [ ... source? func_template ] */ + + if (flags & DUK_COMPILE_NOSOURCE) { + ; + } else { + duk_remove(ctx, -2); + } + + /* [ ... func_template ] */ + + h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1); + DUK_ASSERT(h_templ != NULL); + duk_js_push_closure(thr, + h_templ, + thr->builtins[DUK_BIDX_GLOBAL_ENV], + thr->builtins[DUK_BIDX_GLOBAL_ENV], + 1 /*add_auto_proto*/); + duk_remove(ctx, -2); /* -> [ ... closure ] */ + + /* [ ... closure ] */ + + return 1; +} + +DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { + duk__compile_raw_args comp_args_alloc; + duk__compile_raw_args *comp_args = &comp_args_alloc; + + DUK_ASSERT_CTX_VALID(ctx); + + if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) { + /* String length is computed here to avoid multiple evaluation + * of a macro argument in the calling side. + */ + src_length = DUK_STRLEN(src_buffer); + } + + comp_args->src_buffer = (const duk_uint8_t *) src_buffer; + comp_args->src_length = src_length; + comp_args->flags = flags; + duk_push_pointer(ctx, (void *) comp_args); + + /* [ ... source? filename? &comp_args ] (depends on flags) */ + + if (flags & DUK_COMPILE_SAFE) { + duk_int_t rc; + duk_int_t nargs; + duk_int_t nrets = 1; + + /* Arguments can be: [ source? filename? &comp_args] so that + * nargs is 1 to 3. Call site encodes the correct nargs count + * directly into flags. + */ + nargs = flags & 0x07; + DUK_ASSERT(nargs == (1 + + ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) + + ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1))); + rc = duk_safe_call(ctx, duk__do_compile, nargs, nrets); + + /* [ ... closure ] */ + return rc; + } + + (void) duk__do_compile(ctx); + + /* [ ... closure ] */ + return DUK_EXEC_SUCCESS; +} +/* + * Debugging related API calls + */ + +/* include removed: duk_internal.h */ + +DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) { + duk_idx_t idx; + duk_idx_t top; + + DUK_ASSERT_CTX_VALID(ctx); + + /* We don't duk_require_stack() here now, but rely on the caller having + * enough space. + */ + + top = duk_get_top(ctx); + duk_push_array(ctx); + for (idx = 0; idx < top; idx++) { + duk_dup(ctx, idx); + duk_put_prop_index(ctx, -2, idx); + } + + /* XXX: conversion errors should not propagate outwards. + * Perhaps values need to be coerced individually? + */ + duk_bi_json_stringify_helper(ctx, + duk_get_top_index(ctx), /*idx_value*/ + DUK_INVALID_INDEX, /*idx_replacer*/ + DUK_INVALID_INDEX, /*idx_space*/ + DUK_JSON_FLAG_EXT_CUSTOM | + DUK_JSON_FLAG_ASCII_ONLY | + DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/); + + duk_push_sprintf(ctx, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(ctx, -1)); + duk_replace(ctx, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */ + duk_pop(ctx); + DUK_ASSERT(duk_is_string(ctx, -1)); +} + +#if defined(DUK_USE_DEBUGGER_SUPPORT) + +DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx, + duk_debug_read_function read_cb, + duk_debug_write_function write_cb, + duk_debug_peek_function peek_cb, + duk_debug_read_flush_function read_flush_cb, + duk_debug_write_flush_function write_flush_cb, + duk_debug_request_function request_cb, + duk_debug_detached_function detached_cb, + void *udata) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_heap *heap; + const char *str; + duk_size_t len; + + /* XXX: should there be an error or an automatic detach if + * already attached? + */ + + DUK_D(DUK_DPRINT("application called duk_debugger_attach()")); + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(read_cb != NULL); + DUK_ASSERT(write_cb != NULL); + /* Other callbacks are optional. */ + + heap = thr->heap; + heap->dbg_read_cb = read_cb; + heap->dbg_write_cb = write_cb; + heap->dbg_peek_cb = peek_cb; + heap->dbg_read_flush_cb = read_flush_cb; + heap->dbg_write_flush_cb = write_flush_cb; + heap->dbg_request_cb = request_cb; + heap->dbg_detached_cb = detached_cb; + heap->dbg_udata = udata; + heap->dbg_have_next_byte = 0; + + /* Start in paused state. */ + heap->dbg_processing = 0; + heap->dbg_paused = 1; + heap->dbg_state_dirty = 1; + heap->dbg_force_restart = 0; + heap->dbg_step_type = 0; + heap->dbg_step_thread = NULL; + heap->dbg_step_csindex = 0; + heap->dbg_step_startline = 0; + heap->dbg_exec_counter = 0; + heap->dbg_last_counter = 0; + heap->dbg_last_time = 0.0; + + /* Send version identification and flush right afterwards. Note that + * we must write raw, unframed bytes here. + */ + duk_push_sprintf(ctx, "%ld %ld %s %s\n", + (long) DUK_DEBUG_PROTOCOL_VERSION, + (long) DUK_VERSION, + (const char *) DUK_GIT_DESCRIBE, + (const char *) DUK_USE_TARGET_INFO); + str = duk_get_lstring(ctx, -1, &len); + DUK_ASSERT(str != NULL); + duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len); + duk_debug_write_flush(thr); + duk_pop(ctx); +} + +DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) { + duk_hthread *thr; + + DUK_D(DUK_DPRINT("application called duk_debugger_detach()")); + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + + /* Can be called multiple times with no harm. */ + duk_debug_do_detach(thr->heap); +} + +DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) { + duk_hthread *thr; + duk_bool_t processed_messages; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + + if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + return; + } + if (thr->callstack_top > 0 || thr->heap->dbg_processing) { + /* Calling duk_debugger_cooperate() while Duktape is being + * called into is not supported. This is not a 100% check + * but prevents any damage in most cases. + */ + return; + } + + processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/); + DUK_UNREF(processed_messages); +} + +DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) { + duk_hthread *thr; + duk_idx_t top; + duk_idx_t idx; + duk_bool_t ret = 0; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + + DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues)); + + top = duk_get_top(ctx); + if (top < nvalues) { + DUK_ERROR_API(thr, "not enough stack values for notify"); + return ret; /* unreachable */ + } + if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY); + for (idx = top - nvalues; idx < top; idx++) { + duk_tval *tv = DUK_GET_TVAL_POSIDX(ctx, idx); + duk_debug_write_tval(thr, tv); + } + duk_debug_write_eom(thr); + + /* Return non-zero (true) if we have a good reason to believe + * the notify was delivered; if we're still attached at least + * a transport error was not indicated by the transport write + * callback. This is not a 100% guarantee of course. + */ + if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + ret = 1; + } + } + duk_pop_n(ctx, nvalues); + return ret; +} + +DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) { + duk_hthread *thr; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + + DUK_D(DUK_DPRINT("application called duk_debugger_pause()")); + + /* Treat like a debugger statement: ignore when not attached. */ + if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + DUK_HEAP_SET_PAUSED(thr->heap); + + /* Pause on the next opcode executed. This is always safe to do even + * inside the debugger message loop: the interrupt counter will be reset + * to its proper value when the message loop exits. + */ + thr->interrupt_init = 1; + thr->interrupt_counter = 0; + } +} + +#else /* DUK_USE_DEBUGGER_SUPPORT */ + +DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx, + duk_debug_read_function read_cb, + duk_debug_write_function write_cb, + duk_debug_peek_function peek_cb, + duk_debug_read_flush_function read_flush_cb, + duk_debug_write_flush_function write_flush_cb, + duk_debug_request_function request_cb, + duk_debug_detached_function detached_cb, + void *udata) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(read_cb); + DUK_UNREF(write_cb); + DUK_UNREF(peek_cb); + DUK_UNREF(read_flush_cb); + DUK_UNREF(write_flush_cb); + DUK_UNREF(request_cb); + DUK_UNREF(detached_cb); + DUK_UNREF(udata); + DUK_ERROR_API((duk_hthread *) ctx, "no debugger support"); +} + +DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ERROR_API((duk_hthread *) ctx, "no debugger support"); +} + +DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) { + /* nop */ + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(ctx); +} + +DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) { + duk_idx_t top; + + DUK_ASSERT_CTX_VALID(ctx); + + top = duk_get_top(ctx); + if (top < nvalues) { + DUK_ERROR_API((duk_hthread *) ctx, "not enough stack values for notify"); + return 0; /* unreachable */ + } + + /* No debugger support, just pop values. */ + duk_pop_n(ctx, nvalues); + return 0; +} + +DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) { + /* Treat like debugger statement: nop */ + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(ctx); +} + +#endif /* DUK_USE_DEBUGGER_SUPPORT */ +/* + * Heap creation and destruction + */ + +/* include removed: duk_internal.h */ + +DUK_EXTERNAL +duk_context *duk_create_heap(duk_alloc_function alloc_func, + duk_realloc_function realloc_func, + duk_free_function free_func, + void *heap_udata, + duk_fatal_function fatal_handler) { + duk_heap *heap = NULL; + duk_context *ctx; + + /* Assume that either all memory funcs are NULL or non-NULL, mixed + * cases will now be unsafe. + */ + + /* XXX: just assert non-NULL values here and make caller arguments + * do the defaulting to the default implementations (smaller code)? + */ + + if (!alloc_func) { + DUK_ASSERT(realloc_func == NULL); + DUK_ASSERT(free_func == NULL); +#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) + alloc_func = duk_default_alloc_function; + realloc_func = duk_default_realloc_function; + free_func = duk_default_free_function; +#else + DUK_D(DUK_DPRINT("no allocation functions given and no default providers")); + return NULL; +#endif + } else { + DUK_ASSERT(realloc_func != NULL); + DUK_ASSERT(free_func != NULL); + } + + if (!fatal_handler) { + fatal_handler = duk_default_fatal_handler; + } + + DUK_ASSERT(alloc_func != NULL); + DUK_ASSERT(realloc_func != NULL); + DUK_ASSERT(free_func != NULL); + DUK_ASSERT(fatal_handler != NULL); + + heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler); + if (!heap) { + return NULL; + } + ctx = (duk_context *) heap->heap_thread; + DUK_ASSERT(ctx != NULL); + DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL); + return ctx; +} + +DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_heap *heap; + + if (!ctx) { + return; + } + heap = thr->heap; + DUK_ASSERT(heap != NULL); + + duk_heap_free(heap); +} + +/* XXX: better place for this */ +DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *h_glob; + duk_hobject *h_prev_glob; + duk_hobject *h_env; + duk_hobject *h_prev_env; + + DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1))); + + h_glob = duk_require_hobject(ctx, -1); + DUK_ASSERT(h_glob != NULL); + + /* + * Replace global object. + */ + + h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL]; + DUK_UNREF(h_prev_glob); + thr->builtins[DUK_BIDX_GLOBAL] = h_glob; + DUK_HOBJECT_INCREF(thr, h_glob); + DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */ + + /* + * Replace lexical environment for global scope + * + * Create a new object environment for the global lexical scope. + * We can't just reset the _Target property of the current one, + * because the lexical scope is shared by other threads with the + * same (initial) built-ins. + */ + + (void) duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), + -1); /* no prototype, updated below */ + + duk_dup(ctx, -2); + duk_dup(ctx, -3); + + /* [ ... new_glob new_env new_glob new_glob ] */ + + duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); + duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); + + /* [ ... new_glob new_env ] */ + + h_env = duk_get_hobject(ctx, -1); + DUK_ASSERT(h_env != NULL); + + h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; + thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env; + DUK_HOBJECT_INCREF(thr, h_env); + DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */ + DUK_UNREF(h_env); /* without refcounts */ + DUK_UNREF(h_prev_env); + + /* [ ... new_glob new_env ] */ + + duk_pop_2(ctx); + + /* [ ... ] */ +} +/* + * Logging + * + * Current logging primitive is a sprintf-style log which is convenient + * for most C code. Another useful primitive would be to log N arguments + * from value stack (like the Ecmascript binding does). + */ + +/* include removed: duk_internal.h */ + +DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) { + /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */ + static const duk_uint16_t stridx_logfunc[6] = { + DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO, + DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL + }; + + DUK_ASSERT_CTX_VALID(ctx); + + if (level < 0) { + level = 0; + } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) { + level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1; + } + + duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG); + duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]); + duk_dup(ctx, -2); + + /* [ ... Logger clog logfunc clog ] */ + + duk_push_vsprintf(ctx, fmt, ap); + + /* [ ... Logger clog logfunc clog(=this) msg ] */ + + duk_call_method(ctx, 1 /*nargs*/); + + /* [ ... Logger clog res ] */ + + duk_pop_3(ctx); +} + +DUK_EXTERNAL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...) { + va_list ap; + + DUK_ASSERT_CTX_VALID(ctx); + + va_start(ap, fmt); + duk_log_va(ctx, level, fmt, ap); + va_end(ap); +} +/* + * Memory calls. + */ + +/* include removed: duk_internal.h */ + +DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + + return DUK_ALLOC_RAW(thr->heap, size); +} + +DUK_EXTERNAL void duk_free_raw(duk_context *ctx, void *ptr) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + + DUK_FREE_RAW(thr->heap, ptr); +} + +DUK_EXTERNAL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + + return DUK_REALLOC_RAW(thr->heap, ptr, size); +} + +DUK_EXTERNAL void *duk_alloc(duk_context *ctx, duk_size_t size) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + + return DUK_ALLOC(thr->heap, size); +} + +DUK_EXTERNAL void duk_free(duk_context *ctx, void *ptr) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + + DUK_FREE(thr->heap, ptr); +} + +DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + + /* + * Note: since this is an exposed API call, there should be + * no way a mark-and-sweep could have a side effect on the + * memory allocation behind 'ptr'; the pointer should never + * be something that Duktape wants to change. + * + * Thus, no need to use DUK_REALLOC_INDIRECT (and we don't + * have the storage location here anyway). + */ + + return DUK_REALLOC(thr->heap, ptr, size); +} + +DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_heap *heap; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(out_funcs != NULL); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + + heap = thr->heap; + out_funcs->alloc_func = heap->alloc_func; + out_funcs->realloc_func = heap->realloc_func; + out_funcs->free_func = heap->free_func; + out_funcs->udata = heap->heap_udata; +} + +DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) { +#ifdef DUK_USE_MARK_AND_SWEEP + duk_hthread *thr = (duk_hthread *) ctx; + duk_heap *heap; + + DUK_UNREF(flags); + + /* NULL accepted */ + if (!ctx) { + return; + } + DUK_ASSERT_CTX_VALID(ctx); + heap = thr->heap; + DUK_ASSERT(heap != NULL); + + DUK_D(DUK_DPRINT("mark-and-sweep requested by application")); + duk_heap_mark_and_sweep(heap, 0); +#else + DUK_D(DUK_DPRINT("mark-and-sweep requested by application but mark-and-sweep not enabled, ignoring")); + DUK_UNREF(ctx); + DUK_UNREF(flags); +#endif +} +/* + * Object handling: property access and other support functions. + */ + +/* include removed: duk_internal.h */ + +/* + * Property handling + * + * The API exposes only the most common property handling functions. + * The caller can invoke Ecmascript built-ins for full control (e.g. + * defineProperty, getOwnPropertyDescriptor). + */ + +DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_obj; + duk_tval *tv_key; + duk_bool_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + + /* Note: copying tv_obj and tv_key to locals to shield against a valstack + * resize is not necessary for a property get right now. + */ + + tv_obj = duk_require_tval(ctx, obj_index); + tv_key = duk_require_tval(ctx, -1); + + rc = duk_hobject_getprop(thr, tv_obj, tv_key); + DUK_ASSERT(rc == 0 || rc == 1); + /* a value is left on stack regardless of rc */ + + duk_remove(ctx, -2); /* remove key */ + return rc; /* 1 if property found, 0 otherwise */ +} + +DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(key != NULL); + + obj_index = duk_require_normalize_index(ctx, obj_index); + duk_push_string(ctx, key); + return duk_get_prop(ctx, obj_index); +} + +DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) { + DUK_ASSERT_CTX_VALID(ctx); + + obj_index = duk_require_normalize_index(ctx, obj_index); + duk_push_uarridx(ctx, arr_index); + return duk_get_prop(ctx, obj_index); +} + +DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(stridx >= 0); + DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_UNREF(thr); + + obj_index = duk_require_normalize_index(ctx, obj_index); + duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); + return duk_get_prop(ctx, obj_index); +} + +DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop) { + duk_bool_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(stridx >= 0); + DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + + rc = duk_get_prop_stridx(ctx, obj_index, stridx); + if (out_has_prop) { + *out_has_prop = rc; + } + rc = duk_to_boolean(ctx, -1); + DUK_ASSERT(rc == 0 || rc == 1); + duk_pop(ctx); + return rc; +} + +DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t idx_key) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_obj; + duk_tval *tv_key; + duk_tval *tv_val; + duk_small_int_t throw_flag; + duk_bool_t rc; + + /* Note: copying tv_obj and tv_key to locals to shield against a valstack + * resize is not necessary for a property put right now (putprop protects + * against it internally). + */ + + /* Key and value indices are either (-2, -1) or (-1, -2). Given idx_key, + * idx_val is always (idx_key ^ 0x01). + */ + DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) || + (idx_key == -1 && (idx_key ^ 1) == -2)); + tv_obj = duk_require_tval(ctx, obj_idx); + tv_key = duk_require_tval(ctx, idx_key); + tv_val = duk_require_tval(ctx, idx_key ^ 1); + throw_flag = duk_is_strict_call(ctx); + + rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag); + DUK_ASSERT(rc == 0 || rc == 1); + + duk_pop_2(ctx); /* remove key and value */ + return rc; /* 1 if property found, 0 otherwise */ +} + +DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__put_prop_shared(ctx, obj_idx, -2); +} + +DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(key != NULL); + + /* Careful here and with other duk_put_prop_xxx() helpers: the + * target object and the property value may be in the same value + * stack slot (unusual, but still conceptually clear). + */ + obj_idx = duk_normalize_index(ctx, obj_idx); + (void) duk_push_string(ctx, key); + return duk__put_prop_shared(ctx, obj_idx, -1); +} + +DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { + DUK_ASSERT_CTX_VALID(ctx); + + obj_idx = duk_require_normalize_index(ctx, obj_idx); + duk_push_uarridx(ctx, arr_idx); + return duk__put_prop_shared(ctx, obj_idx, -1); +} + +DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_int_t stridx) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(stridx >= 0); + DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_UNREF(thr); + + obj_idx = duk_require_normalize_index(ctx, obj_idx); + duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); + return duk__put_prop_shared(ctx, obj_idx, -1); +} + +DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_obj; + duk_tval *tv_key; + duk_small_int_t throw_flag; + duk_bool_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + + /* Note: copying tv_obj and tv_key to locals to shield against a valstack + * resize is not necessary for a property delete right now. + */ + + tv_obj = duk_require_tval(ctx, obj_index); + tv_key = duk_require_tval(ctx, -1); + throw_flag = duk_is_strict_call(ctx); + + rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag); + DUK_ASSERT(rc == 0 || rc == 1); + + duk_pop(ctx); /* remove key */ + return rc; +} + +DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(key != NULL); + + obj_index = duk_require_normalize_index(ctx, obj_index); + duk_push_string(ctx, key); + return duk_del_prop(ctx, obj_index); +} + +DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) { + DUK_ASSERT_CTX_VALID(ctx); + + obj_index = duk_require_normalize_index(ctx, obj_index); + duk_push_uarridx(ctx, arr_index); + return duk_del_prop(ctx, obj_index); +} + +DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(stridx >= 0); + DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_UNREF(thr); + + obj_index = duk_require_normalize_index(ctx, obj_index); + duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); + return duk_del_prop(ctx, obj_index); +} + +DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_obj; + duk_tval *tv_key; + duk_bool_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + + /* Note: copying tv_obj and tv_key to locals to shield against a valstack + * resize is not necessary for a property existence check right now. + */ + + tv_obj = duk_require_tval(ctx, obj_index); + tv_key = duk_require_tval(ctx, -1); + + rc = duk_hobject_hasprop(thr, tv_obj, tv_key); + DUK_ASSERT(rc == 0 || rc == 1); + + duk_pop(ctx); /* remove key */ + return rc; /* 1 if property found, 0 otherwise */ +} + +DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(key != NULL); + + obj_index = duk_require_normalize_index(ctx, obj_index); + duk_push_string(ctx, key); + return duk_has_prop(ctx, obj_index); +} + +DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) { + DUK_ASSERT_CTX_VALID(ctx); + + obj_index = duk_require_normalize_index(ctx, obj_index); + duk_push_uarridx(ctx, arr_index); + return duk_has_prop(ctx, obj_index); +} + +DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(stridx >= 0); + DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_UNREF(thr); + + obj_index = duk_require_normalize_index(ctx, obj_index); + duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); + return duk_has_prop(ctx, obj_index); +} + +/* Define own property without inheritance looks and such. This differs from + * [[DefineOwnProperty]] because special behaviors (like Array 'length') are + * not invoked by this method. The caller must be careful to invoke any such + * behaviors if necessary. + */ +DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj; + duk_hstring *key; + + DUK_ASSERT_CTX_VALID(ctx); + + obj = duk_require_hobject(ctx, obj_index); + DUK_ASSERT(obj != NULL); + key = duk_to_hstring(ctx, -2); + DUK_ASSERT(key != NULL); + DUK_ASSERT(duk_require_tval(ctx, -1) != NULL); + + duk_hobject_define_property_internal(thr, obj, key, desc_flags); + + duk_pop(ctx); /* pop key */ +} + +DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj; + + DUK_ASSERT_CTX_VALID(ctx); + + obj = duk_require_hobject(ctx, obj_index); + DUK_ASSERT(obj != NULL); + + duk_hobject_define_property_internal_arridx(thr, obj, arr_index, desc_flags); + /* value popped by call */ +} + +DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj; + duk_hstring *key; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(stridx >= 0); + DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + + obj = duk_require_hobject(ctx, obj_index); + DUK_ASSERT(obj != NULL); + key = DUK_HTHREAD_GET_STRING(thr, stridx); + DUK_ASSERT(key != NULL); + DUK_ASSERT(duk_require_tval(ctx, -1) != NULL); + + duk_hobject_define_property_internal(thr, obj, key, desc_flags); + /* value popped by call */ +} + +DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj; + duk_hstring *key; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(stridx >= 0); + DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + DUK_ASSERT_DISABLE(builtin_idx >= 0); + DUK_ASSERT(builtin_idx < DUK_NUM_BUILTINS); + + obj = duk_require_hobject(ctx, obj_index); + DUK_ASSERT(obj != NULL); + key = DUK_HTHREAD_GET_STRING(thr, stridx); + DUK_ASSERT(key != NULL); + + duk_push_hobject(ctx, thr->builtins[builtin_idx]); + duk_hobject_define_property_internal(thr, obj, key, desc_flags); + /* value popped by call */ +} + +/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3) + * setter/getter into an object property. This is needed by the 'arguments' + * object creation code, function instance creation code, and Function.prototype.bind(). + */ + +DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj = duk_require_hobject(ctx, obj_index); + duk_hobject *thrower = thr->builtins[DUK_BIDX_TYPE_ERROR_THROWER]; + duk_hobject_define_accessor_internal(thr, obj, DUK_HTHREAD_GET_STRING(thr, stridx), thrower, thrower, desc_flags); +} + +/* Object.defineProperty() equivalent C binding. */ +DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t idx_base; + duk_hobject *obj; + duk_hstring *key; + duk_idx_t idx_value; + duk_hobject *get; + duk_hobject *set; + duk_uint_t is_data_desc; + duk_uint_t is_acc_desc; + + DUK_ASSERT_CTX_VALID(ctx); + + obj = duk_require_hobject(ctx, obj_index); + + is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE); + is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); + if (is_data_desc && is_acc_desc) { + /* "Have" flags must not be conflicting so that they would + * apply to both a plain property and an accessor at the same + * time. + */ + goto fail_invalid_desc; + } + + idx_base = duk_get_top_index(ctx); + if (flags & DUK_DEFPROP_HAVE_SETTER) { + duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED | + DUK_TYPE_MASK_OBJECT | + DUK_TYPE_MASK_LIGHTFUNC); + set = duk_get_hobject_or_lfunc_coerce(ctx, idx_base); + if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) { + goto fail_not_callable; + } + idx_base--; + } else { + set = NULL; + } + if (flags & DUK_DEFPROP_HAVE_GETTER) { + duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED | + DUK_TYPE_MASK_OBJECT | + DUK_TYPE_MASK_LIGHTFUNC); + get = duk_get_hobject_or_lfunc_coerce(ctx, idx_base); + if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) { + goto fail_not_callable; + } + idx_base--; + } else { + get = NULL; + } + if (flags & DUK_DEFPROP_HAVE_VALUE) { + idx_value = idx_base; + idx_base--; + } else { + idx_value = (duk_idx_t) -1; + } + key = duk_require_hstring(ctx, idx_base); + + duk_require_valid_index(ctx, idx_base); + + duk_hobject_define_property_helper(ctx, + flags /*defprop_flags*/, + obj, + key, + idx_value, + get, + set); + + /* Clean up stack */ + + duk_set_top(ctx, idx_base); + + /* [ ... obj ... ] */ + + return; + + fail_invalid_desc: + DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR); + return; + + fail_not_callable: + DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE); + return; +} + +/* + * Object related + * + * Note: seal() and freeze() are accessible through Ecmascript bindings, + * and are not exposed through the API. + */ + +DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj; + + DUK_ASSERT_CTX_VALID(ctx); + + obj = duk_get_hobject(ctx, obj_index); + if (obj) { + /* Note: this may fail, caller should protect the call if necessary */ + duk_hobject_compact_props(thr, obj); + } +} + +/* XXX: the duk_hobject_enum.c stack APIs should be reworked */ + +DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags) { + DUK_ASSERT_CTX_VALID(ctx); + + duk_dup(ctx, obj_index); + duk_require_hobject_or_lfunc_coerce(ctx, -1); + duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */ +} + +DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value) { + DUK_ASSERT_CTX_VALID(ctx); + + duk_require_hobject(ctx, enum_index); + duk_dup(ctx, enum_index); + return duk_hobject_enumerator_next(ctx, get_value); +} + +/* + * Helpers for writing multiple properties + */ + +DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs) { + const duk_function_list_entry *ent = funcs; + + DUK_ASSERT_CTX_VALID(ctx); + + obj_index = duk_require_normalize_index(ctx, obj_index); + if (ent != NULL) { + while (ent->key != NULL) { + duk_push_c_function(ctx, ent->value, ent->nargs); + duk_put_prop_string(ctx, obj_index, ent->key); + ent++; + } + } +} + +DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers) { + const duk_number_list_entry *ent = numbers; + + DUK_ASSERT_CTX_VALID(ctx); + + obj_index = duk_require_normalize_index(ctx, obj_index); + if (ent != NULL) { + while (ent->key != NULL) { + duk_push_number(ctx, ent->value); + duk_put_prop_string(ctx, obj_index, ent->key); + ent++; + } + } +} + +/* + * Shortcut for accessing global object properties + */ + +DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_bool_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); + + /* XXX: direct implementation */ + + duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]); + ret = duk_get_prop_string(ctx, -1, key); + duk_remove(ctx, -2); + return ret; +} + +DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_bool_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); + + /* XXX: direct implementation */ + + duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]); + duk_insert(ctx, -2); + ret = duk_put_prop_string(ctx, -2, key); /* [ ... global val ] -> [ ... global ] */ + duk_pop(ctx); + return ret; +} + +/* + * Object prototype + */ + +DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj; + duk_hobject *proto; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(thr); + + obj = duk_require_hobject(ctx, index); + DUK_ASSERT(obj != NULL); + + /* XXX: shared helper for duk_push_hobject_or_undefined()? */ + proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj); + if (proto) { + duk_push_hobject(ctx, proto); + } else { + duk_push_undefined(ctx); + } +} + +DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj; + duk_hobject *proto; + + DUK_ASSERT_CTX_VALID(ctx); + + obj = duk_require_hobject(ctx, index); + DUK_ASSERT(obj != NULL); + duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED | + DUK_TYPE_MASK_OBJECT); + proto = duk_get_hobject(ctx, -1); + /* proto can also be NULL here (allowed explicitly) */ + +#if defined(DUK_USE_ROM_OBJECTS) + if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { + DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */ + return; + } +#endif + + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto); + + duk_pop(ctx); +} + +/* + * Object finalizer + */ + +/* XXX: these could be implemented as macros calling an internal function + * directly. + * XXX: same issue as with Duktape.fin: there's no way to delete the property + * now (just set it to undefined). + */ +DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + + duk_get_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER); +} + +DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + + duk_put_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER); +} +/* + * API calls related to general value stack manipulation: resizing the value + * stack, pushing and popping values, type checking and reading values, + * coercing values, etc. + * + * Also contains internal functions (such as duk_get_tval()), defined + * in duk_api_internal.h, with semantics similar to the public API. + */ + +/* XXX: repetition of stack pre-checks -> helper or macro or inline */ +/* XXX: shared api error strings, and perhaps even throw code for rare cases? */ + +/* include removed: duk_internal.h */ + +/* + * Forward declarations + */ + +DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags); + +/* + * Global state for working around missing variadic macros + */ + +#ifndef DUK_USE_VARIADIC_MACROS +DUK_EXTERNAL const char *duk_api_global_filename = NULL; +DUK_EXTERNAL duk_int_t duk_api_global_line = 0; +#endif + +/* + * Misc helpers + */ + +/* Check that there's room to push one value. */ +#if defined(DUK_USE_VALSTACK_UNSAFE) +/* Faster but value stack overruns are memory unsafe. */ +#define DUK__CHECK_SPACE() do { \ + DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \ + } while (0) +#else +#define DUK__CHECK_SPACE() do { \ + if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \ + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \ + } \ + } while (0) +#endif + +DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag); + +DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_bool_t require) { + duk_hthread *thr; + duk_tval *tv; + duk_small_int_t c; + duk_double_t d; + + thr = (duk_hthread *) ctx; + + tv = duk_get_tval(ctx, index); + if (tv == NULL) { + goto error_notnumber; + } + + /* + * Special cases like NaN and +/- Infinity are handled explicitly + * because a plain C coercion from double to int handles these cases + * in undesirable ways. For instance, NaN may coerce to INT_MIN + * (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX). + * + * This double-to-int coercion differs from ToInteger() because it + * has a finite range (ToInteger() allows e.g. +/- Infinity). It + * also differs from ToInt32() because the INT_MIN/INT_MAX clamping + * depends on the size of the int type on the platform. In particular, + * on platforms with a 64-bit int type, the full range is allowed. + */ + +#if defined(DUK_USE_FASTINT) + if (DUK_TVAL_IS_FASTINT(tv)) { + duk_int64_t t = DUK_TVAL_GET_FASTINT(tv); +#if (DUK_INT_MAX <= 0x7fffffffL) + /* Clamping only necessary for 32-bit ints. */ + if (t < DUK_INT_MIN) { + t = DUK_INT_MIN; + } else if (t > DUK_INT_MAX) { + t = DUK_INT_MAX; + } +#endif + return (duk_int_t) t; + } +#endif + + if (DUK_TVAL_IS_NUMBER(tv)) { + d = DUK_TVAL_GET_NUMBER(tv); + c = (duk_small_int_t) DUK_FPCLASSIFY(d); + if (c == DUK_FP_NAN) { + return 0; + } else if (d < (duk_double_t) DUK_INT_MIN) { + /* covers -Infinity */ + return DUK_INT_MIN; + } else if (d > (duk_double_t) DUK_INT_MAX) { + /* covers +Infinity */ + return DUK_INT_MAX; + } else { + /* coerce towards zero */ + return (duk_int_t) d; + } + } + + error_notnumber: + + if (require) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER); + /* not reachable */ + } + return 0; +} + +DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk_bool_t require) { + duk_hthread *thr; + duk_tval *tv; + duk_small_int_t c; + duk_double_t d; + + /* Same as above but for unsigned int range. */ + + thr = (duk_hthread *) ctx; + + tv = duk_get_tval(ctx, index); + if (tv == NULL) { + goto error_notnumber; + } + +#if defined(DUK_USE_FASTINT) + if (DUK_TVAL_IS_FASTINT(tv)) { + duk_int64_t t = DUK_TVAL_GET_FASTINT(tv); + if (t < 0) { + t = 0; + } +#if (DUK_UINT_MAX <= 0xffffffffUL) + /* Clamping only necessary for 32-bit ints. */ + else if (t > DUK_UINT_MAX) { + t = DUK_UINT_MAX; + } +#endif + return (duk_uint_t) t; + } +#endif + + if (DUK_TVAL_IS_NUMBER(tv)) { + d = DUK_TVAL_GET_NUMBER(tv); + c = (duk_small_int_t) DUK_FPCLASSIFY(d); + if (c == DUK_FP_NAN) { + return 0; + } else if (d < 0.0) { + /* covers -Infinity */ + return (duk_uint_t) 0; + } else if (d > (duk_double_t) DUK_UINT_MAX) { + /* covers +Infinity */ + return (duk_uint_t) DUK_UINT_MAX; + } else { + /* coerce towards zero */ + return (duk_uint_t) d; + } + } + + error_notnumber: + + if (require) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER); + /* not reachable */ + } + return 0; +} + +/* + * Stack index validation/normalization and getting a stack duk_tval ptr. + * + * These are called by many API entrypoints so the implementations must be + * fast and "inlined". + * + * There's some repetition because of this; keep the functions in sync. + */ + +DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_uidx_t vs_size; + duk_uidx_t uindex; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(DUK_INVALID_INDEX < 0); + + /* Care must be taken to avoid pointer wrapping in the index + * validation. For instance, on a 32-bit platform with 8-byte + * duk_tval the index 0x20000000UL would wrap the memory space + * once. + */ + + /* Assume value stack sizes (in elements) fits into duk_idx_t. */ + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); + DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ + + if (index < 0) { + uindex = vs_size + (duk_uidx_t) index; + } else { + /* since index non-negative */ + DUK_ASSERT(index != DUK_INVALID_INDEX); + uindex = (duk_uidx_t) index; + } + + /* DUK_INVALID_INDEX won't be accepted as a valid index. */ + DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); + + if (DUK_LIKELY(uindex < vs_size)) { + return (duk_idx_t) uindex; + } + return DUK_INVALID_INDEX; +} + +DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_uidx_t vs_size; + duk_uidx_t uindex; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(DUK_INVALID_INDEX < 0); + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); + DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ + + if (index < 0) { + uindex = vs_size + (duk_uidx_t) index; + } else { + DUK_ASSERT(index != DUK_INVALID_INDEX); + uindex = (duk_uidx_t) index; + } + + /* DUK_INVALID_INDEX won't be accepted as a valid index. */ + DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); + + if (DUK_LIKELY(uindex < vs_size)) { + return (duk_idx_t) uindex; + } + DUK_ERROR_API_INDEX(thr, index); + return 0; /* unreachable */ +} + +DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_uidx_t vs_size; + duk_uidx_t uindex; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(DUK_INVALID_INDEX < 0); + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); + DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ + + if (index < 0) { + uindex = vs_size + (duk_uidx_t) index; + } else { + DUK_ASSERT(index != DUK_INVALID_INDEX); + uindex = (duk_uidx_t) index; + } + + /* DUK_INVALID_INDEX won't be accepted as a valid index. */ + DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); + + if (DUK_LIKELY(uindex < vs_size)) { + return thr->valstack_bottom + uindex; + } + return NULL; +} + +DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_uidx_t vs_size; + duk_uidx_t uindex; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(DUK_INVALID_INDEX < 0); + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); + DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ + + /* Use unsigned arithmetic to optimize comparison. */ + if (index < 0) { + uindex = vs_size + (duk_uidx_t) index; + } else { + DUK_ASSERT(index != DUK_INVALID_INDEX); + uindex = (duk_uidx_t) index; + } + + /* DUK_INVALID_INDEX won't be accepted as a valid index. */ + DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); + + if (DUK_LIKELY(uindex < vs_size)) { + return thr->valstack_bottom + uindex; + } + DUK_ERROR_API_INDEX(thr, index); + return NULL; +} + +/* Non-critical. */ +DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(DUK_INVALID_INDEX < 0); + + return (duk_normalize_index(ctx, index) >= 0); +} + +/* Non-critical. */ +DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(DUK_INVALID_INDEX < 0); + + if (duk_normalize_index(ctx, index) < 0) { + DUK_ERROR_API_INDEX(thr, index); + return; /* unreachable */ + } +} + +/* + * Value stack top handling + */ + +DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); +} + +/* Set stack top within currently allocated range, but don't reallocate. + * This is performance critical especially for call handling, so whenever + * changing, profile and look at generated code. + */ +DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_uidx_t vs_size; + duk_uidx_t vs_limit; + duk_uidx_t uindex; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(DUK_INVALID_INDEX < 0); + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom); + vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); + vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom); + + if (index < 0) { + /* Negative indices are always within allocated stack but + * must not go below zero index. + */ + uindex = vs_size + (duk_uidx_t) index; + } else { + /* Positive index can be higher than valstack top but must + * not go above allocated stack (equality is OK). + */ + uindex = (duk_uidx_t) index; + } + + /* DUK_INVALID_INDEX won't be accepted as a valid index. */ + DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); + DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit); + +#if defined(DUK_USE_VALSTACK_UNSAFE) + DUK_ASSERT(uindex <= vs_limit); + DUK_UNREF(vs_limit); +#else + if (DUK_UNLIKELY(uindex > vs_limit)) { + DUK_ERROR_API_INDEX(thr, index); + return; /* unreachable */ + } +#endif + DUK_ASSERT(uindex <= vs_limit); + + /* Handle change in value stack top. Respect value stack + * initialization policy: 'undefined' above top. Note that + * DECREF may cause a side effect that reallocates valstack, + * so must relookup after DECREF. + */ + + if (uindex >= vs_size) { + /* Stack size increases or stays the same. */ +#if defined(DUK_USE_ASSERTIONS) + duk_uidx_t count; + + count = uindex - vs_size; + while (count != 0) { + count--; + tv = thr->valstack_top + count; + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); + } +#endif + thr->valstack_top = thr->valstack_bottom + uindex; + } else { + /* Stack size decreases. */ +#if defined(DUK_USE_REFERENCE_COUNTING) + duk_uidx_t count; + + count = vs_size - uindex; + DUK_ASSERT(count > 0); + while (count > 0) { + count--; + tv = --thr->valstack_top; /* tv -> value just before prev top value; must relookup */ + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ + } +#else /* DUK_USE_REFERENCE_COUNTING */ + duk_uidx_t count; + duk_tval *tv_end; + + count = vs_size - uindex; + tv = thr->valstack_top; + tv_end = tv - count; + DUK_ASSERT(tv > tv_end); + do { + tv--; + DUK_TVAL_SET_UNDEFINED(tv); + } while (tv != tv_end); + thr->valstack_top = tv_end; +#endif /* DUK_USE_REFERENCE_COUNTING */ + } +} + +DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1; + if (DUK_UNLIKELY(ret < 0)) { + /* Return invalid index; if caller uses this without checking + * in another API call, the index won't map to a valid stack + * entry. + */ + return DUK_INVALID_INDEX; + } + return ret; +} + +DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1; + if (DUK_UNLIKELY(ret < 0)) { + DUK_ERROR_API_INDEX(thr, -1); + return 0; /* unreachable */ + } + return ret; +} + +/* + * Value stack resizing. + * + * This resizing happens above the current "top": the value stack can be + * grown or shrunk, but the "top" is not affected. The value stack cannot + * be resized to a size below the current "top". + * + * The low level reallocation primitive must carefully recompute all value + * stack pointers, and must also work if ALL pointers are NULL. The resize + * is quite tricky because the valstack realloc may cause a mark-and-sweep, + * which may run finalizers. Running finalizers may resize the valstack + * recursively (the same value stack we're working on). So, after realloc + * returns, we know that the valstack "top" should still be the same (there + * should not be live values above the "top"), but its underlying size and + * pointer may have changed. + */ + +/* XXX: perhaps refactor this to allow caller to specify some parameters, or + * at least a 'compact' flag which skips any spare or round-up .. useful for + * emergency gc. + */ + +DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_ptrdiff_t old_bottom_offset; + duk_ptrdiff_t old_top_offset; + duk_ptrdiff_t old_end_offset_post; +#ifdef DUK_USE_DEBUG + duk_ptrdiff_t old_end_offset_pre; + duk_tval *old_valstack_pre; + duk_tval *old_valstack_post; +#endif + duk_tval *new_valstack; + duk_size_t new_alloc_size; + duk_tval *p; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->valstack_bottom >= thr->valstack); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_end >= thr->valstack_top); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */ + DUK_ASSERT(new_size <= thr->valstack_max); /* valstack limit caller has check, prevents wrapping */ + DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */ + + /* get pointer offsets for tweaking below */ + old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)); + old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)); +#ifdef DUK_USE_DEBUG + old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* not very useful, used for debugging */ + old_valstack_pre = thr->valstack; +#endif + + /* Allocate a new valstack. + * + * Note: cannot use a plain DUK_REALLOC() because a mark-and-sweep may + * invalidate the original thr->valstack base pointer inside the realloc + * process. See doc/memory-management.rst. + */ + + new_alloc_size = sizeof(duk_tval) * new_size; + new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size); + if (!new_valstack) { + /* Because new_size != 0, if condition doesn't need to be + * (new_valstack != NULL || new_size == 0). + */ + DUK_ASSERT(new_size != 0); + DUK_D(DUK_DPRINT("failed to resize valstack to %lu entries (%lu bytes)", + (unsigned long) new_size, (unsigned long) new_alloc_size)); + return 0; + } + + /* Note: the realloc may have triggered a mark-and-sweep which may + * have resized our valstack internally. However, the mark-and-sweep + * MUST NOT leave the stack bottom/top in a different state. Particular + * assumptions and facts: + * + * - The thr->valstack pointer may be different after realloc, + * and the offset between thr->valstack_end <-> thr->valstack + * may have changed. + * - The offset between thr->valstack_bottom <-> thr->valstack + * and thr->valstack_top <-> thr->valstack MUST NOT have changed, + * because mark-and-sweep must adhere to a strict stack policy. + * In other words, logical bottom and top MUST NOT have changed. + * - All values above the top are unreachable but are initialized + * to UNDEFINED, up to the post-realloc valstack_end. + * - 'old_end_offset' must be computed after realloc to be correct. + */ + + DUK_ASSERT((((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)) == old_bottom_offset); + DUK_ASSERT((((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)) == old_top_offset); + + /* success, fixup pointers */ + old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* must be computed after realloc */ +#ifdef DUK_USE_DEBUG + old_valstack_post = thr->valstack; +#endif + thr->valstack = new_valstack; + thr->valstack_end = new_valstack + new_size; +#if !defined(DUK_USE_PREFER_SIZE) + thr->valstack_size = new_size; +#endif + thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_bottom_offset); + thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_top_offset); + + DUK_ASSERT(thr->valstack_bottom >= thr->valstack); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_end >= thr->valstack_top); + + /* useful for debugging */ +#ifdef DUK_USE_DEBUG + if (old_end_offset_pre != old_end_offset_post) { + DUK_D(DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; " + "end offset changed: %lu -> %lu", + (unsigned long) old_end_offset_pre, + (unsigned long) old_end_offset_post)); + } + if (old_valstack_pre != old_valstack_post) { + DUK_D(DUK_DPRINT("valstack pointer changed during valstack_resize(), probably by mark-and-sweep: %p -> %p", + (void *) old_valstack_pre, + (void *) old_valstack_post)); + } +#endif + + DUK_DD(DUK_DDPRINT("resized valstack to %lu elements (%lu bytes), bottom=%ld, top=%ld, " + "new pointers: start=%p end=%p bottom=%p top=%p", + (unsigned long) new_size, (unsigned long) new_alloc_size, + (long) (thr->valstack_bottom - thr->valstack), + (long) (thr->valstack_top - thr->valstack), + (void *) thr->valstack, (void *) thr->valstack_end, + (void *) thr->valstack_bottom, (void *) thr->valstack_top)); + + /* Init newly allocated slots (only). */ + p = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + old_end_offset_post); + while (p < thr->valstack_end) { + /* Never executed if new size is smaller. */ + DUK_TVAL_SET_UNDEFINED(p); + p++; + } + + /* Assert for value stack initialization policy. */ +#if defined(DUK_USE_ASSERTIONS) + p = thr->valstack_top; + while (p < thr->valstack_end) { + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p)); + p++; + } +#endif + + return 1; +} + +DUK_INTERNAL +duk_bool_t duk_valstack_resize_raw(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_size_t old_size; + duk_size_t new_size; + duk_bool_t is_shrink = 0; + duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK); + duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT); + duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW); + + DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, " + "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d", + (unsigned long) min_new_size, + (long) (thr->valstack_end - thr->valstack), + (long) (thr->valstack_top - thr->valstack), + (long) (thr->valstack_bottom - thr->valstack), + (int) shrink_flag, (int) compact_flag, (int) throw_flag)); + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->valstack_bottom >= thr->valstack); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_end >= thr->valstack_top); + +#if defined(DUK_USE_PREFER_SIZE) + old_size = (duk_size_t) (thr->valstack_end - thr->valstack); +#else + DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size); + old_size = thr->valstack_size; +#endif + + if (min_new_size <= old_size) { + is_shrink = 1; + if (!shrink_flag || + old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) { + DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack")); + return 1; + } + } + + new_size = min_new_size; + if (!compact_flag) { + if (is_shrink) { + /* shrink case; leave some spare */ + new_size += DUK_VALSTACK_SHRINK_SPARE; + } + + /* round up roughly to next 'grow step' */ + new_size = (new_size / DUK_VALSTACK_GROW_STEP + 1) * DUK_VALSTACK_GROW_STEP; + } + + DUK_DD(DUK_DDPRINT("want to %s valstack: %lu -> %lu elements (min_new_size %lu)", + (const char *) (new_size > old_size ? "grow" : "shrink"), + (unsigned long) old_size, (unsigned long) new_size, + (unsigned long) min_new_size)); + + if (new_size > thr->valstack_max) { + /* Note: may be triggered even if minimal new_size would not reach the limit, + * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account). + */ + if (throw_flag) { + DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT); + } else { + return 0; + } + } + + /* + * When resizing the valstack, a mark-and-sweep may be triggered for + * the allocation of the new valstack. If the mark-and-sweep needs + * to use our thread for something, it may cause *the same valstack* + * to be resized recursively. This happens e.g. when mark-and-sweep + * finalizers are called. This is taken into account carefully in + * duk__resize_valstack(). + * + * 'new_size' is known to be <= valstack_max, which ensures that + * size_t and pointer arithmetic won't wrap in duk__resize_valstack(). + */ + + if (!duk__resize_valstack(ctx, new_size)) { + if (is_shrink) { + DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore")); + return 1; + } + + DUK_DD(DUK_DDPRINT("valstack resize failed")); + + if (throw_flag) { + DUK_ERROR_ALLOC_DEFMSG(thr); + } else { + return 0; + } + } + + DUK_DDD(DUK_DDDPRINT("valstack resize successful")); + return 1; +} + +DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_size_t min_new_size; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + if (DUK_UNLIKELY(extra < 0)) { + /* Clamping to zero makes the API more robust to calling code + * calculation errors. + */ + extra = 0; + } + + min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA; + return duk_valstack_resize_raw(ctx, + min_new_size, /* min_new_size */ + 0 /* no shrink */ | /* flags */ + 0 /* no compact */ | + 0 /* no throw */); +} + +DUK_EXTERNAL void duk_require_stack(duk_context *ctx, duk_idx_t extra) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_size_t min_new_size; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + if (DUK_UNLIKELY(extra < 0)) { + /* Clamping to zero makes the API more robust to calling code + * calculation errors. + */ + extra = 0; + } + + min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA; + (void) duk_valstack_resize_raw(ctx, + min_new_size, /* min_new_size */ + 0 /* no shrink */ | /* flags */ + 0 /* no compact */ | + DUK_VSRESIZE_FLAG_THROW); +} + +DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) { + duk_size_t min_new_size; + + DUK_ASSERT_CTX_VALID(ctx); + + if (DUK_UNLIKELY(top < 0)) { + /* Clamping to zero makes the API more robust to calling code + * calculation errors. + */ + top = 0; + } + + min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + return duk_valstack_resize_raw(ctx, + min_new_size, /* min_new_size */ + 0 /* no shrink */ | /* flags */ + 0 /* no compact */ | + 0 /* no throw */); +} + +DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) { + duk_size_t min_new_size; + + DUK_ASSERT_CTX_VALID(ctx); + + if (DUK_UNLIKELY(top < 0)) { + /* Clamping to zero makes the API more robust to calling code + * calculation errors. + */ + top = 0; + } + + min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + (void) duk_valstack_resize_raw(ctx, + min_new_size, /* min_new_size */ + 0 /* no shrink */ | /* flags */ + 0 /* no compact */ | + DUK_VSRESIZE_FLAG_THROW); +} + +/* + * Basic stack manipulation: swap, dup, insert, replace, etc + */ + +DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) { + duk_tval *tv1; + duk_tval *tv2; + duk_tval tv_tmp; + + DUK_ASSERT_CTX_VALID(ctx); + + tv1 = duk_require_tval(ctx, index1); + DUK_ASSERT(tv1 != NULL); + tv2 = duk_require_tval(ctx, index2); + DUK_ASSERT(tv2 != NULL); + + /* If tv1==tv2 this is a NOP, no check is needed */ + DUK_TVAL_SET_TVAL(&tv_tmp, tv1); + DUK_TVAL_SET_TVAL(tv1, tv2); + DUK_TVAL_SET_TVAL(tv2, &tv_tmp); +} + +DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + + duk_swap(ctx, index, -1); +} + +DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) { + duk_hthread *thr; + duk_tval *tv_from; + duk_tval *tv_to; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + + tv_from = duk_require_tval(ctx, from_index); + tv_to = thr->valstack_top++; + DUK_ASSERT(tv_from != NULL); + DUK_ASSERT(tv_to != NULL); + DUK_TVAL_SET_TVAL(tv_to, tv_from); + DUK_TVAL_INCREF(thr, tv_to); /* no side effects */ +} + +DUK_EXTERNAL void duk_dup_top(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv_from; + duk_tval *tv_to; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + + if (thr->valstack_top - thr->valstack_bottom <= 0) { + DUK_ERROR_API_INDEX(thr, -1); + return; /* unreachable */ + } + tv_from = thr->valstack_top - 1; + tv_to = thr->valstack_top++; + DUK_ASSERT(tv_from != NULL); + DUK_ASSERT(tv_to != NULL); + DUK_TVAL_SET_TVAL(tv_to, tv_from); + DUK_TVAL_INCREF(thr, tv_to); /* no side effects */ +} + +DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) { + duk_tval *p; + duk_tval *q; + duk_tval tv_tmp; + duk_size_t nbytes; + + DUK_ASSERT_CTX_VALID(ctx); + + p = duk_require_tval(ctx, to_index); + DUK_ASSERT(p != NULL); + q = duk_require_tval(ctx, -1); + DUK_ASSERT(q != NULL); + + DUK_ASSERT(q >= p); + + /* nbytes + * <---------> + * [ ... | p | x | x | q ] + * => [ ... | q | p | x | x ] + */ + + nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */ + + DUK_DDD(DUK_DDDPRINT("duk_insert: to_index=%ld, p=%p, q=%p, nbytes=%lu", + (long) to_index, (void *) p, (void *) q, (unsigned long) nbytes)); + + /* No net refcount changes. */ + + if (nbytes > 0) { + DUK_TVAL_SET_TVAL(&tv_tmp, q); + DUK_ASSERT(nbytes > 0); + DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes); + DUK_TVAL_SET_TVAL(p, &tv_tmp); + } else { + /* nop: insert top to top */ + DUK_ASSERT(nbytes == 0); + DUK_ASSERT(p == q); + } +} + +DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv1; + duk_tval *tv2; + duk_tval tv_tmp; + + DUK_ASSERT_CTX_VALID(ctx); + + tv1 = duk_require_tval(ctx, -1); + DUK_ASSERT(tv1 != NULL); + tv2 = duk_require_tval(ctx, to_index); + DUK_ASSERT(tv2 != NULL); + + /* For tv1 == tv2, both pointing to stack top, the end result + * is same as duk_pop(ctx). + */ + DUK_TVAL_SET_TVAL(&tv_tmp, tv2); + DUK_TVAL_SET_TVAL(tv2, tv1); + DUK_TVAL_SET_UNDEFINED(tv1); + thr->valstack_top--; + DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ +} + +DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv1; + duk_tval *tv2; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(thr); /* w/o refcounting */ + + tv1 = duk_require_tval(ctx, from_index); + DUK_ASSERT(tv1 != NULL); + tv2 = duk_require_tval(ctx, to_index); + DUK_ASSERT(tv2 != NULL); + + /* For tv1 == tv2, this is a no-op (no explicit check needed). */ + DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */ +} + +DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *p; + duk_tval *q; +#ifdef DUK_USE_REFERENCE_COUNTING + duk_tval tv_tmp; +#endif + duk_size_t nbytes; + + DUK_ASSERT_CTX_VALID(ctx); + + p = duk_require_tval(ctx, index); + DUK_ASSERT(p != NULL); + q = duk_require_tval(ctx, -1); + DUK_ASSERT(q != NULL); + + DUK_ASSERT(q >= p); + + /* nbytes zero size case + * <---------> + * [ ... | p | x | x | q ] [ ... | p==q ] + * => [ ... | x | x | q ] [ ... ] + */ + +#ifdef DUK_USE_REFERENCE_COUNTING + /* use a temp: decref only when valstack reachable values are correct */ + DUK_TVAL_SET_TVAL(&tv_tmp, p); +#endif + + nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */ + DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */ + + DUK_TVAL_SET_UNDEFINED(q); + thr->valstack_top--; + +#ifdef DUK_USE_REFERENCE_COUNTING + DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ +#endif +} + +/* + * Stack slice primitives + */ + +DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy) { + duk_hthread *to_thr = (duk_hthread *) to_ctx; + duk_hthread *from_thr = (duk_hthread *) from_ctx; + void *src; + duk_size_t nbytes; + duk_tval *p; + duk_tval *q; + + /* XXX: several pointer comparison issues here */ + + DUK_ASSERT_CTX_VALID(to_ctx); + DUK_ASSERT_CTX_VALID(from_ctx); + DUK_ASSERT(to_ctx != NULL); + DUK_ASSERT(from_ctx != NULL); + + if (to_ctx == from_ctx) { + DUK_ERROR_API(to_thr, DUK_STR_INVALID_CONTEXT); + return; + } + if ((count < 0) || + (count > (duk_idx_t) to_thr->valstack_max)) { + /* Maximum value check ensures 'nbytes' won't wrap below. */ + DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT); + return; + } + + nbytes = sizeof(duk_tval) * count; + if (nbytes == 0) { + return; + } + DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end); + if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) { + DUK_ERROR_API(to_thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + } + src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); + if (src < (void *) from_thr->valstack_bottom) { + DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT); + } + + /* copy values (no overlap even if to_ctx == from_ctx; that's not + * allowed now anyway) + */ + DUK_ASSERT(nbytes > 0); + DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes); + + p = to_thr->valstack_top; + to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes); + + if (is_copy) { + /* Incref copies, keep originals. */ + q = to_thr->valstack_top; + while (p < q) { + DUK_TVAL_INCREF(to_thr, p); /* no side effects */ + p++; + } + } else { + /* No net refcount change. */ + p = from_thr->valstack_top; + q = (duk_tval *) (void *) (((duk_uint8_t *) p) - nbytes); + from_thr->valstack_top = q; + + while (p > q) { + p--; + DUK_TVAL_SET_UNDEFINED(p); + /* XXX: fast primitive to set a bunch of values to UNDEFINED */ + } + } +} + +/* + * Get/require + */ + +DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_UNDEFINED(tv)) { + return; + } + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "undefined", DUK_STR_NOT_UNDEFINED); + return; /* not reachable */ +} + +DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_NULL(tv)) { + return; + } + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "null", DUK_STR_NOT_NULL); + return; /* not reachable */ +} + +DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index) { + duk_bool_t ret = 0; /* default: false */ + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_BOOLEAN(tv)) { + ret = DUK_TVAL_GET_BOOLEAN(tv); + } + + DUK_ASSERT(ret == 0 || ret == 1); + return ret; +} + +DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_BOOLEAN(tv)) { + duk_bool_t ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + return ret; + } + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "boolean", DUK_STR_NOT_BOOLEAN); + return 0; /* not reachable */ +} + +DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index) { + duk_double_union ret; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + ret.d = DUK_DOUBLE_NAN; /* default: NaN */ + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_NUMBER(tv)) { + ret.d = DUK_TVAL_GET_NUMBER(tv); + } + + /* + * Number should already be in NaN-normalized form, but let's + * normalize anyway. + */ + + DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret); + return ret.d; +} + +DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_NUMBER(tv)) { + duk_double_union ret; + ret.d = DUK_TVAL_GET_NUMBER(tv); + + /* + * Number should already be in NaN-normalized form, + * but let's normalize anyway. + */ + + DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret); + return ret.d; + } + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER); + return DUK_DOUBLE_NAN; /* not reachable */ +} + +DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index) { + /* Custom coercion for API */ + DUK_ASSERT_CTX_VALID(ctx); + return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/); +} + +DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index) { + /* Custom coercion for API */ + DUK_ASSERT_CTX_VALID(ctx); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/); +} + +DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index) { + /* Custom coercion for API */ + DUK_ASSERT_CTX_VALID(ctx); + return (duk_int_t) duk__api_coerce_d2i(ctx, index, 1 /*require*/); +} + +DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index) { + /* Custom coercion for API */ + DUK_ASSERT_CTX_VALID(ctx); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 1 /*require*/); +} + +DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { + const char *ret; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + /* default: NULL, length 0 */ + ret = NULL; + if (out_len) { + *out_len = 0; + } + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_STRING(tv)) { + /* Here we rely on duk_hstring instances always being zero + * terminated even if the actual string is not. + */ + duk_hstring *h = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h != NULL); + ret = (const char *) DUK_HSTRING_GET_DATA(h); + if (out_len) { + *out_len = DUK_HSTRING_GET_BYTELEN(h); + } + } + + return ret; +} + +DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { + duk_hthread *thr = (duk_hthread *) ctx; + const char *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + /* Note: this check relies on the fact that even a zero-size string + * has a non-NULL pointer. + */ + ret = duk_get_lstring(ctx, index, out_len); + if (ret) { + return ret; + } + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "string", DUK_STR_NOT_STRING); + return NULL; /* not reachable */ +} + +DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk_get_lstring(ctx, index, NULL); +} + +DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk_require_lstring(ctx, index, NULL); +} + +DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_POINTER(tv)) { + void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ + return (void *) p; + } + + return NULL; +} + +DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + /* Note: here we must be wary of the fact that a pointer may be + * valid and be a NULL. + */ + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_POINTER(tv)) { + void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ + return (void *) p; + } + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "pointer", DUK_STR_NOT_POINTER); + return NULL; /* not reachable */ +} + +#if 0 /*unused*/ +DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); + DUK_ASSERT(h != NULL); + return (void *) h; + } + + return NULL; +} +#endif + +DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(thr); + + if (out_size != NULL) { + *out_size = 0; + } + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_BUFFER(tv)) { + duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + if (out_size) { + *out_size = DUK_HBUFFER_GET_SIZE(h); + } + return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ + } + + if (throw_flag) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER); + } + return NULL; +} + +DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { + return duk__get_buffer_helper(ctx, index, out_size, 0 /*throw_flag*/); +} + +DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { + return duk__get_buffer_helper(ctx, index, out_size, 1 /*throw_flag*/); +} + +DUK_LOCAL void *duk__get_buffer_data_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(thr); + + if (out_size != NULL) { + *out_size = 0; + } + + tv = duk_get_tval(ctx, index); + if (tv == NULL) { + goto fail; + } + + if (DUK_TVAL_IS_BUFFER(tv)) { + duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + if (out_size) { + *out_size = DUK_HBUFFER_GET_SIZE(h); + } + return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ + } else if (DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) { + /* XXX: this is probably a useful shared helper: for a + * duk_hbufferobject, get a validated buffer pointer/length. + */ + duk_hbufferobject *h_bufobj = (duk_hbufferobject *) h; + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + if (h_bufobj->buf != NULL && + DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) { + duk_uint8_t *p; + + p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf); + if (out_size != NULL) { + *out_size = (duk_size_t) h_bufobj->length; + } + return (void *) (p + h_bufobj->offset); + } + /* if slice not fully valid, treat as error */ + } + } + + fail: + if (throw_flag) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER); + } + return NULL; +} + +DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { + return duk__get_buffer_data_helper(ctx, index, out_size, 0 /*throw_flag*/); +} + +DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { + return duk__get_buffer_data_helper(ctx, index, out_size, 1 /*throw_flag*/); +} + +/* Raw helper for getting a value from the stack, checking its tag. + * The tag cannot be a number because numbers don't have an internal + * tag in the packed representation. + */ + +DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && (DUK_TVAL_GET_TAG(tv) == tag)) { + duk_heaphdr *ret; + ret = DUK_TVAL_GET_HEAPHDR(tv); + DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */ + return ret; + } + + return (duk_heaphdr *) NULL; +} + +DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index) { + return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING); +} + +DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index) { + duk_heaphdr *h; + h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING); + if (h == NULL) { + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "string", DUK_STR_NOT_STRING); + } + return (duk_hstring *) h; +} + +DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index) { + return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); +} + +DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index) { + duk_heaphdr *h; + h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (h == NULL) { + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "object", DUK_STR_NOT_OBJECT); + } + return (duk_hobject *) h; +} + +DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index) { + return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER); +} + +DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index) { + duk_heaphdr *h; + h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER); + if (h == NULL) { + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "buffer", DUK_STR_NOT_BUFFER); + } + return (duk_hbuffer *) h; +} + +DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) { + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) { + h = NULL; + } + return (duk_hthread *) h; +} + +DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "thread", DUK_STR_NOT_THREAD); + } + return (duk_hthread *) h; +} + +DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index) { + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) { + h = NULL; + } + return (duk_hcompiledfunction *) h; +} + +DUK_INTERNAL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(h))) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "compiledfunction", DUK_STR_NOT_COMPILEDFUNCTION); + } + return (duk_hcompiledfunction *) h; +} + +DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index) { + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { + h = NULL; + } + return (duk_hnativefunction *) h; +} + +DUK_INTERNAL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_IS_NATIVEFUNCTION(h))) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION); + } + return (duk_hnativefunction *) h; +} + +DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + duk_hobject *h; + duk_hnativefunction *f; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (!tv) { + return NULL; + } + if (!DUK_TVAL_IS_OBJECT(tv)) { + return NULL; + } + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + + if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { + return NULL; + } + DUK_ASSERT(DUK_HOBJECT_HAS_NATIVEFUNCTION(h)); + f = (duk_hnativefunction *) h; + + return f->func; +} + +DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_c_function ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_c_function(ctx, index); + if (!ret) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION); + } + return ret; +} + +DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t index) { + if (!duk_is_function(ctx, index)) { + DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, index, "function", DUK_STR_NOT_FUNCTION); + } +} + +DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_context *) duk_get_hthread(ctx, index); +} + +DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_context *) duk_require_hthread(ctx, index); +} + +DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + void *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); + DUK_ASSERT(ret != NULL); + return ret; + } + + return (void *) NULL; +} + +DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + void *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); + DUK_ASSERT(ret != NULL); + return ret; + } + + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "heapobject", DUK_STR_UNEXPECTED_TYPE); + return (void *) NULL; /* not reachable */ +} + +#if 0 +/* This would be pointless: we'd return NULL for both lightfuncs and + * unexpected types. + */ +DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) { +} +#endif + +/* Useful for internal call sites where we either expect an object (function) + * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced + * to an object). Return value is NULL if value is neither an object nor a + * lightfunc. + */ +DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_OBJECT(tv)) { + return DUK_TVAL_GET_OBJECT(tv); + } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { + duk_to_object(ctx, index); + return duk_require_hobject(ctx, index); + } + + return NULL; +} + +/* Useful for internal call sites where we either expect an object (function) + * or a lightfunc. Returns NULL for a lightfunc. + */ +DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_OBJECT(tv)) { + return DUK_TVAL_GET_OBJECT(tv); + } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { + return NULL; + } + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT); + return NULL; /* not reachable */ +} + +/* Useful for internal call sites where we either expect an object (function) + * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced + * to an object). Return value is never NULL. + */ +DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + if (DUK_TVAL_IS_OBJECT(tv)) { + return DUK_TVAL_GET_OBJECT(tv); + } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { + duk_to_object(ctx, index); + return duk_require_hobject(ctx, index); + } + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT); + return NULL; /* not reachable */ +} + +DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) { + duk_hobject *h; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */ + DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); + + h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) { + h = NULL; + } + return h; +} + +DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) { + duk_hthread *thr; + duk_hobject *h; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */ + DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); + thr = (duk_hthread *) ctx; + + h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) { + duk_hstring *h_class; + h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum)); + DUK_UNREF(h_class); + + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE); + } + return h; +} + +DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (!tv) { + return 0; + } + + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNDEFINED: + case DUK_TAG_NULL: + case DUK_TAG_BOOLEAN: + case DUK_TAG_POINTER: + return 0; + case DUK_TAG_STRING: { + duk_hstring *h = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h != NULL); + return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h); + } + case DUK_TAG_OBJECT: { + duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h); + } + case DUK_TAG_BUFFER: { + duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + return (duk_size_t) DUK_HBUFFER_GET_SIZE(h); + } + case DUK_TAG_LIGHTFUNC: { + duk_small_uint_t lf_flags; + lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); + return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags); + } +#if defined(DUK_USE_FASTINT) + case DUK_TAG_FASTINT: +#endif + default: + /* number */ + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + return 0; + } + + DUK_UNREACHABLE(); +} + +DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *h; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hobject(ctx, index); + if (!h) { + return; + } + + duk_hobject_set_length(thr, h, (duk_uint32_t) length); /* XXX: typing */ +} + +/* + * Conversions and coercions + * + * The conversion/coercions are in-place operations on the value stack. + * Some operations are implemented here directly, while others call a + * helper in duk_js_ops.c after validating arguments. + */ + +/* E5 Section 8.12.8 */ + +DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t index, duk_small_int_t func_stridx) { + if (duk_get_prop_stridx(ctx, index, func_stridx)) { + /* [ ... func ] */ + if (duk_is_callable(ctx, -1)) { + duk_dup(ctx, index); /* -> [ ... func this ] */ + duk_call_method(ctx, 0); /* -> [ ... retval ] */ + if (duk_is_primitive(ctx, -1)) { + duk_replace(ctx, index); + return 1; + } + /* [ ... retval ]; popped below */ + } + } + duk_pop(ctx); /* [ ... func/retval ] -> [ ... ] */ + return 0; +} + +DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj; + /* inline initializer for coercers[] is not allowed by old compilers like BCC */ + duk_small_int_t coercers[2]; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + coercers[0] = DUK_STRIDX_VALUE_OF; + coercers[1] = DUK_STRIDX_TO_STRING; + + index = duk_require_normalize_index(ctx, index); + obj = duk_require_hobject_or_lfunc(ctx, index); + + if (hint == DUK_HINT_NONE) { + if (obj != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_DATE) { + hint = DUK_HINT_STRING; + } else { + hint = DUK_HINT_NUMBER; + } + } + + if (hint == DUK_HINT_STRING) { + coercers[0] = DUK_STRIDX_TO_STRING; + coercers[1] = DUK_STRIDX_VALUE_OF; + } + + if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[0])) { + return; + } + + if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[1])) { + return; + } + + DUK_ERROR_TYPE(thr, DUK_STR_DEFAULTVALUE_COERCE_FAILED); +} + +DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(thr); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ +} + +DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(thr); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */ +} + +/* E5 Section 9.1 */ +DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint) { + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING); + + index = duk_require_normalize_index(ctx, index); + + if (!duk_check_type_mask(ctx, index, DUK_TYPE_MASK_OBJECT | + DUK_TYPE_MASK_LIGHTFUNC)) { + /* everything except object stay as is */ + return; + } + duk_to_defaultvalue(ctx, index, hint); +} + +/* E5 Section 9.2 */ +DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_bool_t val; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(thr); + + index = duk_require_normalize_index(ctx, index); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + + val = duk_js_toboolean(tv); + DUK_ASSERT(val == 0 || val == 1); + + /* Note: no need to re-lookup tv, conversion is side effect free */ + DUK_ASSERT(tv != NULL); + DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */ + return val; +} + +DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_double_t d; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + /* XXX: fastint? */ + d = duk_js_tonumber(thr, tv); + + /* Note: need to re-lookup because ToNumber() may have side effects */ + tv = duk_require_tval(ctx, index); + DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */ + return d; +} + +/* XXX: combine all the integer conversions: they share everything + * but the helper function for coercion. + */ + +typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv); + +DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t index, duk__toint_coercer coerce_func) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_double_t d; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + d = coerce_func(thr, tv); + + /* XXX: fastint? */ + + /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ + tv = duk_require_tval(ctx, index); + DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */ + return d; +} + +DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index) { + /* Value coercion (in stack): ToInteger(), E5 Section 9.4 + * API return value coercion: custom + */ + DUK_ASSERT_CTX_VALID(ctx); + (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger); + return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/); +} + +DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index) { + /* Value coercion (in stack): ToInteger(), E5 Section 9.4 + * API return value coercion: custom + */ + DUK_ASSERT_CTX_VALID(ctx); + (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/); +} + +DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_int32_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + ret = duk_js_toint32(thr, tv); + + /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ + tv = duk_require_tval(ctx, index); + DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv, ret); /* side effects */ + return ret; +} + +DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_uint32_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + ret = duk_js_touint32(thr, tv); + + /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ + tv = duk_require_tval(ctx, index); + DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */ + return ret; +} + +DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_uint16_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + ret = duk_js_touint16(thr, tv); + + /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ + tv = duk_require_tval(ctx, index); + DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */ + return ret; +} + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Special coercion for Uint8ClampedArray. */ +DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index) { + duk_double_t d; + duk_double_t t; + duk_uint8_t ret; + + /* XXX: Simplify this algorithm, should be possible to come up with + * a shorter and faster algorithm by inspecting IEEE representation + * directly. + */ + + d = duk_to_number(ctx, index); + if (d <= 0.0) { + return 0; + } else if (d >= 255) { + return 255; + } else if (DUK_ISNAN(d)) { + /* Avoid NaN-to-integer coercion as it is compiler specific. */ + return 0; + } + + t = d - DUK_FLOOR(d); + if (t == 0.5) { + /* Exact halfway, round to even. */ + ret = (duk_uint8_t) d; + ret = (ret + 1) & 0xfe; /* Example: d=3.5, t=0.5 -> ret = (3 + 1) & 0xfe = 4 & 0xfe = 4 + * Example: d=4.5, t=0.5 -> ret = (4 + 1) & 0xfe = 5 & 0xfe = 4 + */ + } else { + /* Not halfway, round to nearest. */ + ret = (duk_uint8_t) (d + 0.5); + } + return ret; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { + DUK_ASSERT_CTX_VALID(ctx); + + (void) duk_to_string(ctx, index); + return duk_require_lstring(ctx, index, out_len); +} + +DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + + duk_to_string(ctx, -1); + return 1; +} + +DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_require_normalize_index(ctx, index); + + /* We intentionally ignore the duk_safe_call() return value and only + * check the output type. This way we don't also need to check that + * the returned value is indeed a string in the success case. + */ + + duk_dup(ctx, index); + (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/); + if (!duk_is_string(ctx, -1)) { + /* Error: try coercing error to string once. */ + (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/); + if (!duk_is_string(ctx, -1)) { + /* Double error */ + duk_pop(ctx); + duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_ERROR); + } else { + ; + } + } else { + ; + } + DUK_ASSERT(duk_is_string(ctx, -1)); + DUK_ASSERT(duk_get_string(ctx, -1) != NULL); + + duk_replace(ctx, index); + return duk_get_lstring(ctx, index, out_len); +} + +#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ +DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index) { + (void) duk_safe_to_string(ctx, index); + DUK_ASSERT(duk_is_string(ctx, index)); + DUK_ASSERT(duk_get_hstring(ctx, index) != NULL); + return duk_get_hstring(ctx, index); +} +#endif + +/* Coerce top into Object.prototype.toString() output. */ +DUK_INTERNAL void duk_to_object_class_string_top(duk_context *ctx) { + duk_hthread *thr; + duk_uint_t typemask; + duk_hstring *h_strclass; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + typemask = duk_get_type_mask(ctx, -1); + if (typemask & DUK_TYPE_MASK_UNDEFINED) { + h_strclass = DUK_HTHREAD_STRING_UC_UNDEFINED(thr); + } else if (typemask & DUK_TYPE_MASK_NULL) { + h_strclass = DUK_HTHREAD_STRING_UC_NULL(thr); + } else { + duk_hobject *h_obj; + + duk_to_object(ctx, -1); + h_obj = duk_get_hobject(ctx, -1); + DUK_ASSERT(h_obj != NULL); + + h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_obj); + } + DUK_ASSERT(h_strclass != NULL); + + duk_pop(ctx); + duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass)); +} + +#if !defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h) { + duk_hthread *thr; + duk_hstring *h_strclass; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(h != NULL); + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h); + DUK_ASSERT(h_strclass != NULL); + duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass)); +} +#endif /* !DUK_USE_PARANOID_ERRORS */ + +/* XXX: other variants like uint, u32 etc */ +DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_tval tv_tmp; + duk_double_t d, dmin, dmax; + duk_int_t res; + duk_bool_t clamped = 0; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */ + + dmin = (duk_double_t) minval; + dmax = (duk_double_t) maxval; + + if (d < dmin) { + clamped = 1; + res = minval; + d = dmin; + } else if (d > dmax) { + clamped = 1; + res = maxval; + d = dmax; + } else { + res = (duk_int_t) d; + } + DUK_UNREF(d); /* SCANBUILD: with suitable dmin/dmax limits 'd' is unused */ + /* 'd' and 'res' agree here */ + + /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */ + tv = duk_get_tval(ctx, index); + DUK_ASSERT(tv != NULL); /* not popped by side effect */ + DUK_TVAL_SET_TVAL(&tv_tmp, tv); +#if defined(DUK_USE_FASTINT) +#if (DUK_INT_MAX <= 0x7fffffffL) + DUK_TVAL_SET_FASTINT_I32(tv, res); +#else + /* Clamping needed if duk_int_t is 64 bits. */ + if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) { + DUK_TVAL_SET_FASTINT(tv, res); + } else { + DUK_TVAL_SET_NUMBER(tv, d); + } +#endif +#else + DUK_TVAL_SET_NUMBER(tv, d); /* no need to incref */ +#endif + DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ + + if (out_clamped) { + *out_clamped = clamped; + } else { + /* coerced value is updated to value stack even when RangeError thrown */ + if (clamped) { + DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE); + } + } + + return res; +} + +DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_idx_t minval, duk_idx_t maxval) { + duk_bool_t dummy; + return duk_to_int_clamped_raw(ctx, index, minval, maxval, &dummy); +} + +DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval) { + return duk_to_int_clamped_raw(ctx, index, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */ +} + +DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(thr); + + index = duk_require_normalize_index(ctx, index); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNDEFINED: { + duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED); + break; + } + case DUK_TAG_NULL: { + duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL); + break; + } + case DUK_TAG_BOOLEAN: { + if (DUK_TVAL_GET_BOOLEAN(tv)) { + duk_push_hstring_stridx(ctx, DUK_STRIDX_TRUE); + } else { + duk_push_hstring_stridx(ctx, DUK_STRIDX_FALSE); + } + break; + } + case DUK_TAG_STRING: { + /* nop */ + goto skip_replace; + } + case DUK_TAG_OBJECT: { + duk_to_primitive(ctx, index, DUK_HINT_STRING); + return duk_to_string(ctx, index); /* Note: recursive call */ + } + case DUK_TAG_BUFFER: { + duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); + + /* Note: this allows creation of internal strings. */ + + DUK_ASSERT(h != NULL); + duk_push_lstring(ctx, + (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h), + (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); + break; + } + case DUK_TAG_POINTER: { + void *ptr = DUK_TVAL_GET_POINTER(tv); + if (ptr != NULL) { + duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) ptr); + } else { + /* Represent a null pointer as 'null' to be consistent with + * the JX format variant. Native '%p' format for a NULL + * pointer may be e.g. '(nil)'. + */ + duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL); + } + break; + } + case DUK_TAG_LIGHTFUNC: { + /* Should match Function.prototype.toString() */ + duk_push_lightfunc_tostring(ctx, tv); + break; + } +#if defined(DUK_USE_FASTINT) + case DUK_TAG_FASTINT: +#endif + default: { + /* number */ + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + duk_push_tval(ctx, tv); + duk_numconv_stringify(ctx, + 10 /*radix*/, + 0 /*precision:shortest*/, + 0 /*force_exponential*/); + break; + } + } + + duk_replace(ctx, index); + + skip_replace: + return duk_require_string(ctx, index); +} + +DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index) { + duk_hstring *ret; + DUK_ASSERT_CTX_VALID(ctx); + duk_to_string(ctx, index); + ret = duk_get_hstring(ctx, index); + DUK_ASSERT(ret != NULL); + return ret; +} + +DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t mode) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hbuffer *h_buf; + const duk_uint8_t *src_data; + duk_size_t src_size; + duk_uint8_t *dst_data; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(thr); + + index = duk_require_normalize_index(ctx, index); + + h_buf = duk_get_hbuffer(ctx, index); + if (h_buf != NULL) { + /* Buffer is kept as is, with the fixed/dynamic nature of the + * buffer only changed if requested. An external buffer + * is converted into a non-external dynamic buffer in a + * duk_to_dynamic_buffer() call. + */ + duk_uint_t tmp; + duk_uint8_t *tmp_ptr; + + tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf); + src_data = (const duk_uint8_t *) tmp_ptr; + src_size = DUK_HBUFFER_GET_SIZE(h_buf); + + tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED); + if ((tmp == mode && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)) || + mode == DUK_BUF_MODE_DONTCARE) { + /* Note: src_data may be NULL if input is a zero-size + * dynamic buffer. + */ + dst_data = tmp_ptr; + goto skip_copy; + } + } else { + /* Non-buffer value is first ToString() coerced, then converted + * to a buffer (fixed buffer is used unless a dynamic buffer is + * explicitly requested). + */ + + src_data = (const duk_uint8_t *) duk_to_lstring(ctx, index, &src_size); + } + + dst_data = (duk_uint8_t *) duk_push_buffer(ctx, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/); + if (DUK_LIKELY(src_size > 0)) { + /* When src_size == 0, src_data may be NULL (if source + * buffer is dynamic), and dst_data may be NULL (if + * target buffer is dynamic). Avoid zero-size memcpy() + * with an invalid pointer. + */ + DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size); + } + duk_replace(ctx, index); + skip_copy: + + if (out_size) { + *out_size = src_size; + } + return dst_data; +} + +DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + void *res; + + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_require_normalize_index(ctx, index); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNDEFINED: + case DUK_TAG_NULL: + case DUK_TAG_BOOLEAN: + res = NULL; + break; + case DUK_TAG_POINTER: + res = DUK_TVAL_GET_POINTER(tv); + break; + case DUK_TAG_STRING: + case DUK_TAG_OBJECT: + case DUK_TAG_BUFFER: + /* Heap allocated: return heap pointer which is NOT useful + * for the caller, except for debugging. + */ + res = (void *) DUK_TVAL_GET_HEAPHDR(tv); + break; + case DUK_TAG_LIGHTFUNC: + /* Function pointers do not always cast correctly to void * + * (depends on memory and segmentation model for instance), + * so they coerce to NULL. + */ + res = NULL; + break; +#if defined(DUK_USE_FASTINT) + case DUK_TAG_FASTINT: +#endif + default: + /* number */ + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + res = NULL; + break; + } + + duk_push_pointer(ctx, res); + duk_replace(ctx, index); + return res; +} + +DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_uint_t flags = 0; /* shared flags for a subset of types */ + duk_small_int_t proto = 0; + + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_require_normalize_index(ctx, index); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNDEFINED: + case DUK_TAG_NULL: { + DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE); + break; + } + case DUK_TAG_BOOLEAN: { + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN); + proto = DUK_BIDX_BOOLEAN_PROTOTYPE; + goto create_object; + } + case DUK_TAG_STRING: { + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); + proto = DUK_BIDX_STRING_PROTOTYPE; + goto create_object; + } + case DUK_TAG_OBJECT: { + /* nop */ + break; + } + case DUK_TAG_BUFFER: { + /* A plain buffer coerces to a Duktape.Buffer because it's the + * object counterpart of the plain buffer value. But it might + * still make more sense to produce an ArrayBuffer here? + */ + + duk_hbufferobject *h_bufobj; + duk_hbuffer *h_val; + + h_val = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h_val != NULL); + + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER), + DUK_BIDX_BUFFER_PROTOTYPE); + DUK_ASSERT(h_bufobj != NULL); + DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE((duk_hobject *) h_bufobj)); + DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj)); + + h_bufobj->buf = h_val; + DUK_HBUFFER_INCREF(thr, h_val); + DUK_ASSERT(h_bufobj->offset == 0); + h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val); + DUK_ASSERT(h_bufobj->shift == 0); + DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8); + + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + goto replace_value; + } + case DUK_TAG_POINTER: { + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER); + proto = DUK_BIDX_POINTER_PROTOTYPE; + goto create_object; + } + case DUK_TAG_LIGHTFUNC: { + /* Lightfunc coerces to a Function instance with concrete + * properties. Since 'length' is virtual for Duktape/C + * functions, don't need to define that. + * + * The result is made extensible to mimic what happens to + * strings: + * > Object.isExtensible(Object('foo')) + * true + */ + duk_small_uint_t lf_flags; + duk_idx_t nargs; + duk_small_uint_t lf_len; + duk_c_function func; + duk_hnativefunction *nf; + + DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); + + nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags); + if (nargs == DUK_LFUNC_NARGS_VARARGS) { + nargs = (duk_idx_t) DUK_VARARGS; + } + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_NATIVEFUNCTION | + DUK_HOBJECT_FLAG_NEWENV | + DUK_HOBJECT_FLAG_STRICT | + DUK_HOBJECT_FLAG_NOTAIL | + /* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */ + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); + (void) duk__push_c_function_raw(ctx, func, nargs, flags); + + lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags); + if ((duk_idx_t) lf_len != nargs) { + /* Explicit length is only needed if it differs from 'nargs'. */ + duk_push_int(ctx, (duk_int_t) lf_len); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); + } + duk_push_lightfunc_name(ctx, tv); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); + + nf = duk_get_hnativefunction(ctx, -1); + DUK_ASSERT(nf != NULL); + nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); + + /* Enable DUKFUNC exotic behavior once properties are set up. */ + DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf); + goto replace_value; + } +#if defined(DUK_USE_FASTINT) + case DUK_TAG_FASTINT: +#endif + default: { + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); + proto = DUK_BIDX_NUMBER_PROTOTYPE; + goto create_object; + } + } + return; + + create_object: + (void) duk_push_object_helper(ctx, flags, proto); + + /* Note: Boolean prototype's internal value property is not writable, + * but duk_xdef_prop_stridx() disregards the write protection. Boolean + * instances are immutable. + * + * String and buffer special behaviors are already enabled which is not + * ideal, but a write to the internal value is not affected by them. + */ + duk_dup(ctx, index); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); + + replace_value: + duk_replace(ctx, index); +} + +/* + * Type checking + */ + +DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t index, duk_small_uint_t tag) { + duk_tval *tv; + + tv = duk_get_tval(ctx, index); + if (!tv) { + return 0; + } + return (DUK_TVAL_GET_TAG(tv) == tag); +} + +DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t index, duk_uint_t flag_mask) { + duk_hobject *obj; + + DUK_ASSERT_CTX_VALID(ctx); + + obj = duk_get_hobject(ctx, index); + if (obj) { + return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0); + } + return 0; +} + +DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (!tv) { + return DUK_TYPE_NONE; + } + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNDEFINED: + return DUK_TYPE_UNDEFINED; + case DUK_TAG_NULL: + return DUK_TYPE_NULL; + case DUK_TAG_BOOLEAN: + return DUK_TYPE_BOOLEAN; + case DUK_TAG_STRING: + return DUK_TYPE_STRING; + case DUK_TAG_OBJECT: + return DUK_TYPE_OBJECT; + case DUK_TAG_BUFFER: + return DUK_TYPE_BUFFER; + case DUK_TAG_POINTER: + return DUK_TYPE_POINTER; + case DUK_TAG_LIGHTFUNC: + return DUK_TYPE_LIGHTFUNC; +#if defined(DUK_USE_FASTINT) + case DUK_TAG_FASTINT: +#endif + default: + /* Note: number has no explicit tag (in 8-byte representation) */ + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + return DUK_TYPE_NUMBER; + } + DUK_UNREACHABLE(); +} + +#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS) +DUK_LOCAL const char *duk__type_names[] = { + "none", + "undefined", + "null", + "boolean", + "number", + "string", + "object", + "buffer", + "pointer", + "lightfunc" +}; + +DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) { + duk_int_t type_tag; + + type_tag = duk_get_type(ctx, index); + DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX); + DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1); + + return duk__type_names[type_tag]; +} +#endif + +DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_get_type(ctx, index) == type) ? 1 : 0; +} + +DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (!tv) { + return DUK_TYPE_MASK_NONE; + } + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNDEFINED: + return DUK_TYPE_MASK_UNDEFINED; + case DUK_TAG_NULL: + return DUK_TYPE_MASK_NULL; + case DUK_TAG_BOOLEAN: + return DUK_TYPE_MASK_BOOLEAN; + case DUK_TAG_STRING: + return DUK_TYPE_MASK_STRING; + case DUK_TAG_OBJECT: + return DUK_TYPE_MASK_OBJECT; + case DUK_TAG_BUFFER: + return DUK_TYPE_MASK_BUFFER; + case DUK_TAG_POINTER: + return DUK_TYPE_MASK_POINTER; + case DUK_TAG_LIGHTFUNC: + return DUK_TYPE_MASK_LIGHTFUNC; +#if defined(DUK_USE_FASTINT) + case DUK_TAG_FASTINT: +#endif + default: + /* Note: number has no explicit tag (in 8-byte representation) */ + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + return DUK_TYPE_MASK_NUMBER; + } + DUK_UNREACHABLE(); +} + +DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_get_type_mask(ctx, index) & mask) { + return 1; + } + if (mask & DUK_TYPE_MASK_THROW) { + DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); + DUK_UNREACHABLE(); + } + return 0; +} + +DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, index, DUK_TAG_UNDEFINED); +} + +DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, index, DUK_TAG_NULL); +} + +DUK_EXTERNAL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + duk_small_uint_t tag; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (!tv) { + return 0; + } + tag = DUK_TVAL_GET_TAG(tv); + return (tag == DUK_TAG_UNDEFINED) || (tag == DUK_TAG_NULL); +} + +DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, index, DUK_TAG_BOOLEAN); +} + +DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + /* + * Number is special because it doesn't have a specific + * tag in the 8-byte representation. + */ + + /* XXX: shorter version for 12-byte representation? */ + + tv = duk_get_tval(ctx, index); + if (!tv) { + return 0; + } + return DUK_TVAL_IS_NUMBER(tv); +} + +DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) { + /* XXX: This will now return false for non-numbers, even though they would + * coerce to NaN (as a general rule). In particular, duk_get_number() + * returns a NaN for non-numbers, so should this function also return + * true for non-numbers? + */ + + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (!tv || !DUK_TVAL_IS_NUMBER(tv)) { + return 0; + } + return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv)); +} + +DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, index, DUK_TAG_STRING); +} + +DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, index, DUK_TAG_OBJECT); +} + +DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, index, DUK_TAG_BUFFER); +} + +DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, index, DUK_TAG_POINTER); +} + +DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__tag_check(ctx, index, DUK_TAG_LIGHTFUNC); +} + +DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index) { + duk_hobject *obj; + + DUK_ASSERT_CTX_VALID(ctx); + + obj = duk_get_hobject(ctx, index); + if (obj) { + return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0); + } + return 0; +} + +DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_LIGHTFUNC(tv)) { + return 1; + } + return duk__obj_flag_any_default_false(ctx, + index, + DUK_HOBJECT_FLAG_COMPILEDFUNCTION | + DUK_HOBJECT_FLAG_NATIVEFUNCTION | + DUK_HOBJECT_FLAG_BOUND); +} + +DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__obj_flag_any_default_false(ctx, + index, + DUK_HOBJECT_FLAG_NATIVEFUNCTION); +} + +DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__obj_flag_any_default_false(ctx, + index, + DUK_HOBJECT_FLAG_COMPILEDFUNCTION); +} + +DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__obj_flag_any_default_false(ctx, + index, + DUK_HOBJECT_FLAG_BOUND); +} + +DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk__obj_flag_any_default_false(ctx, + index, + DUK_HOBJECT_FLAG_THREAD); +} + +DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_BUFFER(tv)) { + duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1); + } + return 0; +} + +DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_BUFFER(tv)) { + duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0); + } + return 0; +} + +DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index) { + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_get_tval(ctx, index); + if (tv && DUK_TVAL_IS_BUFFER(tv)) { + duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0); + } + return 0; +} + +DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *h; + duk_uint_t sanity; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hobject(ctx, index); + + sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; + do { + if (!h) { + return DUK_ERR_NONE; + } + if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) { + return DUK_ERR_EVAL_ERROR; + } + if (h == thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]) { + return DUK_ERR_RANGE_ERROR; + } + if (h == thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]) { + return DUK_ERR_REFERENCE_ERROR; + } + if (h == thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]) { + return DUK_ERR_SYNTAX_ERROR; + } + if (h == thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]) { + return DUK_ERR_TYPE_ERROR; + } + if (h == thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]) { + return DUK_ERR_URI_ERROR; + } + if (h == thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]) { + return DUK_ERR_ERROR; + } + + h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); + } while (--sanity > 0); + + return DUK_ERR_NONE; +} + +/* + * Pushers + */ + +DUK_INTERNAL void duk_push_tval(duk_context *ctx, duk_tval *tv) { + duk_hthread *thr; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(tv != NULL); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_TVAL(tv_slot, tv); + DUK_TVAL_INCREF(thr, tv); /* no side effects */ +} + +DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) { + duk_hthread *thr; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + + /* Because value stack init policy is 'undefined above top', + * we don't need to write, just assert. + */ + thr->valstack_top++; + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1)); +} + +DUK_EXTERNAL void duk_push_null(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_NULL(tv_slot); +} + +DUK_EXTERNAL void duk_push_boolean(duk_context *ctx, duk_bool_t val) { + duk_hthread *thr; + duk_tval *tv_slot; + duk_small_int_t b; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */ + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_BOOLEAN(tv_slot, b); +} + +DUK_EXTERNAL void duk_push_true(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot); +} + +DUK_EXTERNAL void duk_push_false(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot); +} + +/* normalize NaN which may not match our canonical internal NaN */ +DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) { + duk_hthread *thr; + duk_tval *tv_slot; + duk_double_union du; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + du.d = val; + DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_NUMBER(tv_slot, du.d); +} + +DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) { +#if defined(DUK_USE_FASTINT) + duk_hthread *thr; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + tv_slot = thr->valstack_top++; +#if DUK_INT_MAX <= 0x7fffffffL + DUK_TVAL_SET_FASTINT_I32(tv_slot, (duk_int32_t) val); +#else + if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) { + DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val); + } else { + duk_double_t = (duk_double_t) val; + DUK_TVAL_SET_NUMBER(tv_slot, d); + } +#endif +#else /* DUK_USE_FASTINT */ + duk_hthread *thr; + duk_tval *tv_slot; + duk_double_t d; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + d = (duk_double_t) val; + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_NUMBER(tv_slot, d); +#endif /* DUK_USE_FASTINT */ +} + +DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) { +#if defined(DUK_USE_FASTINT) + duk_hthread *thr; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + tv_slot = thr->valstack_top++; +#if DUK_UINT_MAX <= 0xffffffffUL + DUK_TVAL_SET_FASTINT_U32(tv_slot, (duk_uint32_t) val); +#else + if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */ + /* XXX: take advantage of val being unsigned, no need to mask */ + DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val); + } else { + duk_double_t = (duk_double_t) val; + DUK_TVAL_SET_NUMBER(tv_slot, d); + } +#endif +#else /* DUK_USE_FASTINT */ + duk_hthread *thr; + duk_tval *tv_slot; + duk_double_t d; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + d = (duk_double_t) val; + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_NUMBER(tv_slot, d); +#endif /* DUK_USE_FASTINT */ +} + +DUK_EXTERNAL void duk_push_nan(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv_slot; + duk_double_union du; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + DUK_DBLUNION_SET_NAN(&du); + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_NUMBER(tv_slot, du.d); +} + +DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hstring *h; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + + /* check stack before interning (avoid hanging temp) */ + if (thr->valstack_top >= thr->valstack_end) { + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + } + + /* NULL with zero length represents an empty string; NULL with higher + * length is also now trated like an empty string although it is + * a bit dubious. This is unlike duk_push_string() which pushes a + * 'null' if the input string is a NULL. + */ + if (!str) { + len = 0; + } + + /* Check for maximum string length */ + if (len > DUK_HSTRING_MAX_BYTELEN) { + DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); + } + + h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); + DUK_ASSERT(h != NULL); + + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_STRING(tv_slot, h); + DUK_HSTRING_INCREF(thr, h); /* no side effects */ + + return (const char *) DUK_HSTRING_GET_DATA(h); +} + +DUK_EXTERNAL const char *duk_push_string(duk_context *ctx, const char *str) { + DUK_ASSERT_CTX_VALID(ctx); + + if (str) { + return duk_push_lstring(ctx, str, DUK_STRLEN(str)); + } else { + duk_push_null(ctx); + return NULL; + } +} + +#ifdef DUK_USE_FILE_IO +/* This is a bit clunky because it is ANSI C portable. Should perhaps + * relocate to another file because this is potentially platform + * dependent. + */ +DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_file *f = NULL; + char *buf; + long sz; /* ANSI C typing */ + + DUK_ASSERT_CTX_VALID(ctx); + + if (!path) { + goto fail; + } + f = DUK_FOPEN(path, "rb"); + if (!f) { + goto fail; + } + if (DUK_FSEEK(f, 0, SEEK_END) < 0) { + goto fail; + } + sz = DUK_FTELL(f); + if (sz < 0) { + goto fail; + } + if (DUK_FSEEK(f, 0, SEEK_SET) < 0) { + goto fail; + } + buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) sz); + DUK_ASSERT(buf != NULL); + if ((duk_size_t) DUK_FREAD(buf, 1, (size_t) sz, f) != (duk_size_t) sz) { + goto fail; + } + (void) DUK_FCLOSE(f); /* ignore fclose() error */ + f = NULL; + return duk_to_string(ctx, -1); + + fail: + if (f) { + DUK_FCLOSE(f); + } + + if (flags != 0) { + DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */ + duk_push_undefined(ctx); + } else { + /* XXX: string not shared because it is conditional */ + DUK_ERROR_TYPE(thr, "read file error"); + } + return NULL; +} +#else +DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(path); + + if (flags != 0) { + DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */ + duk_push_undefined(ctx); + } else { + /* XXX: string not shared because it is conditional */ + DUK_ERROR_UNSUPPORTED(thr, "file I/O disabled"); + } + return NULL; +} +#endif /* DUK_USE_FILE_IO */ + +DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) { + duk_hthread *thr; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK__CHECK_SPACE(); + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_POINTER(tv_slot, val); +} + +DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_object_coercible) { + duk_hthread *thr; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ + thr = (duk_hthread *) ctx; + DUK_ASSERT(thr->callstack_top <= thr->callstack_size); + DUK__CHECK_SPACE(); + + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */ + tv_slot = thr->valstack_top++; + + if (DUK_UNLIKELY(thr->callstack_top == 0)) { + if (check_object_coercible) { + goto type_error; + } + /* 'undefined' already on stack top */ + } else { + duk_tval *tv; + + /* 'this' binding is just before current activation's bottom */ + DUK_ASSERT(thr->valstack_bottom > thr->valstack); + tv = thr->valstack_bottom - 1; + if (check_object_coercible && + (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv))) { + /* XXX: better macro for DUK_TVAL_IS_UNDEFINED_OR_NULL(tv) */ + goto type_error; + } + + DUK_TVAL_SET_TVAL(tv_slot, tv); + DUK_TVAL_INCREF(thr, tv); + } + return; + + type_error: + DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE); +} + +DUK_EXTERNAL void duk_push_this(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + + duk__push_this_helper(ctx, 0 /*check_object_coercible*/); +} + +DUK_INTERNAL void duk_push_this_check_object_coercible(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + + duk__push_this_helper(ctx, 1 /*check_object_coercible*/); +} + +DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) { + duk_hobject *h; + + DUK_ASSERT_CTX_VALID(ctx); + + duk__push_this_helper(ctx, 1 /*check_object_coercible*/); + duk_to_object(ctx, -1); + h = duk_get_hobject(ctx, -1); + DUK_ASSERT(h != NULL); + return h; +} + +DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) { + duk_hstring *h; + + DUK_ASSERT_CTX_VALID(ctx); + + duk__push_this_helper(ctx, 1 /*check_object_coercible*/); + duk_to_string(ctx, -1); + h = duk_get_hstring(ctx, -1); + DUK_ASSERT(h != NULL); + return h; +} + +DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx) { + duk_hthread *thr; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + + DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */ + DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */ + DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */ + + return thr->valstack_bottom - 1; +} + +DUK_EXTERNAL void duk_push_current_function(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); + DUK_ASSERT(thr->callstack_top <= thr->callstack_size); + + act = duk_hthread_get_current_activation(thr); + if (act) { + duk_push_tval(ctx, &act->tv_func); + } else { + duk_push_undefined(ctx); + } +} + +DUK_EXTERNAL void duk_push_current_thread(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + if (thr->heap->curr_thread) { + duk_push_hobject(ctx, (duk_hobject *) thr->heap->curr_thread); + } else { + duk_push_undefined(ctx); + } +} + +DUK_EXTERNAL void duk_push_global_object(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + + duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL); +} + +/* XXX: size optimize */ +DUK_LOCAL void duk__push_stash(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE)) { + DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use")); + duk_pop(ctx); + duk_push_object_internal(ctx); + duk_dup_top(ctx); + duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */ + } + duk_remove(ctx, -2); +} + +DUK_EXTERNAL void duk_push_heap_stash(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_heap *heap; + DUK_ASSERT_CTX_VALID(ctx); + heap = thr->heap; + DUK_ASSERT(heap->heap_object != NULL); + duk_push_hobject(ctx, heap->heap_object); + duk__push_stash(ctx); +} + +DUK_EXTERNAL void duk_push_global_stash(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + duk_push_global_object(ctx); + duk__push_stash(ctx); +} + +DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + DUK_ASSERT_CTX_VALID(ctx); + if (!target_ctx) { + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + return; /* not reached */ + } + duk_push_hobject(ctx, (duk_hobject *) target_ctx); + duk__push_stash(ctx); +} + +/* XXX: duk_ssize_t would be useful here */ +DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size_t sz, const char *fmt, va_list ap) { + duk_int_t len; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_UNREF(ctx); + + /* NUL terminator handling doesn't matter here */ + len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap); + if (len < (duk_int_t) sz) { + /* Return value of 'sz' or more indicates output was (potentially) + * truncated. + */ + return (duk_int_t) len; + } + return -1; +} + +DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE]; + duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE; + duk_bool_t pushed_buf = 0; + void *buf; + duk_int_t len; /* XXX: duk_ssize_t */ + const char *res; + + DUK_ASSERT_CTX_VALID(ctx); + + /* special handling of fmt==NULL */ + if (!fmt) { + duk_hstring *h_str; + duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); + h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); /* rely on interning, must be this string */ + return (const char *) DUK_HSTRING_GET_DATA(h_str); + } + + /* initial estimate based on format string */ + sz = DUK_STRLEN(fmt) + 16; /* format plus something to avoid just missing */ + if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) { + sz = DUK_PUSH_SPRINTF_INITIAL_SIZE; + } + DUK_ASSERT(sz > 0); + + /* Try to make do with a stack buffer to avoid allocating a temporary buffer. + * This works 99% of the time which is quite nice. + */ + for (;;) { + va_list ap_copy; /* copied so that 'ap' can be reused */ + + if (sz <= sizeof(stack_buf)) { + buf = stack_buf; + } else if (!pushed_buf) { + pushed_buf = 1; + buf = duk_push_dynamic_buffer(ctx, sz); + } else { + buf = duk_resize_buffer(ctx, -1, sz); + } + DUK_ASSERT(buf != NULL); + + DUK_VA_COPY(ap_copy, ap); + len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap_copy); + va_end(ap_copy); + if (len >= 0) { + break; + } + + /* failed, resize and try again */ + sz = sz * 2; + if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) { + DUK_ERROR_API(thr, DUK_STR_SPRINTF_TOO_LONG); + } + } + + /* Cannot use duk_to_string() on the buffer because it is usually + * larger than 'len'. Also, 'buf' is usually a stack buffer. + */ + res = duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */ + if (pushed_buf) { + duk_remove(ctx, -2); + } + return res; +} + +DUK_EXTERNAL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...) { + va_list ap; + const char *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + /* allow fmt==NULL */ + va_start(ap, fmt); + ret = duk_push_vsprintf(ctx, fmt, ap); + va_end(ap); + + return ret; +} + +DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_slot; + duk_hobject *h; + duk_idx_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(prototype_bidx == -1 || + (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS)); + + /* check stack first */ + if (thr->valstack_top >= thr->valstack_end) { + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + } + + h = duk_hobject_alloc(thr->heap, hobject_flags_and_class); + if (!h) { + DUK_ERROR_ALLOC_DEFMSG(thr); + } + + DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags)); + + tv_slot = thr->valstack_top; + DUK_TVAL_SET_OBJECT(tv_slot, h); + DUK_HOBJECT_INCREF(thr, h); /* no side effects */ + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + thr->valstack_top++; + + /* object is now reachable */ + + if (prototype_bidx >= 0) { + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[prototype_bidx]); + } else { + DUK_ASSERT(prototype_bidx == -1); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL); + } + + return ret; +} + +DUK_INTERNAL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t ret; + duk_hobject *h; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_push_object_helper(ctx, hobject_flags_and_class, -1); + h = duk_get_hobject(ctx, -1); + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL); + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto); + return ret; +} + +DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), + DUK_BIDX_OBJECT_PROTOTYPE); +} + +DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *obj; + duk_idx_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_ARRAY_PART | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY), + DUK_BIDX_ARRAY_PROTOTYPE); + + obj = duk_require_hobject(ctx, ret); + + /* + * An array must have a 'length' property (E5 Section 15.4.5.2). + * The special array behavior flag must only be enabled once the + * length property has been added. + * + * The internal property must be a number (and preferably a + * fastint if fastint support is enabled). + */ + + duk_push_int(ctx, 0); +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(duk_require_tval(ctx, -1))); +#endif + + duk_hobject_define_property_internal(thr, + obj, + DUK_HTHREAD_STRING_LENGTH(thr), + DUK_PROPDESC_FLAGS_W); + DUK_HOBJECT_SET_EXOTIC_ARRAY(obj); + + return ret; +} + +DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hthread *obj; + duk_idx_t ret; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + + /* check stack first */ + if (thr->valstack_top >= thr->valstack_end) { + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + } + + obj = duk_hthread_alloc(thr->heap, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_THREAD | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); + if (!obj) { + DUK_ERROR_ALLOC_DEFMSG(thr); + } + obj->state = DUK_HTHREAD_STATE_INACTIVE; +#if defined(DUK_USE_ROM_STRINGS) + /* Nothing to initialize, strs[] is in ROM. */ +#else +#if defined(DUK_USE_HEAPPTR16) + obj->strs16 = thr->strs16; +#else + obj->strs = thr->strs; +#endif +#endif + DUK_DDD(DUK_DDDPRINT("created thread object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags)); + + /* make the new thread reachable */ + tv_slot = thr->valstack_top; + DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); + DUK_HTHREAD_INCREF(thr, obj); + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + thr->valstack_top++; + + /* important to do this *after* pushing, to make the thread reachable for gc */ + if (!duk_hthread_init_stacks(thr->heap, obj)) { + DUK_ERROR_ALLOC_DEFMSG(thr); + } + + /* initialize built-ins - either by copying or creating new ones */ + if (flags & DUK_THREAD_NEW_GLOBAL_ENV) { + duk_hthread_create_builtin_objects(obj); + } else { + duk_hthread_copy_builtin_objects(thr, obj); + } + + /* default prototype (Note: 'obj' must be reachable) */ + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]); + + /* Initial stack size satisfies the stack spare constraints so there + * is no need to require stack here. + */ + DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >= + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); + + return ret; +} + +DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hcompiledfunction *obj; + duk_idx_t ret; + duk_tval *tv_slot; + + DUK_ASSERT_CTX_VALID(ctx); + + /* check stack first */ + if (thr->valstack_top >= thr->valstack_end) { + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + } + + /* Template functions are not strictly constructable (they don't + * have a "prototype" property for instance), so leave the + * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here. + */ + + obj = duk_hcompiledfunction_alloc(thr->heap, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_COMPILEDFUNCTION | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); + if (!obj) { + DUK_ERROR_ALLOC_DEFMSG(thr); + } + + DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags)); + + tv_slot = thr->valstack_top; + DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); + DUK_HOBJECT_INCREF(thr, obj); + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + thr->valstack_top++; + + /* default prototype (Note: 'obj' must be reachable) */ + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); + + return ret; +} + +DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hnativefunction *obj; + duk_idx_t ret; + duk_tval *tv_slot; + duk_int16_t func_nargs; + + DUK_ASSERT_CTX_VALID(ctx); + + /* check stack first */ + if (thr->valstack_top >= thr->valstack_end) { + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + } + if (func == NULL) { + goto api_error; + } + if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) { + func_nargs = (duk_int16_t) nargs; + } else if (nargs == DUK_VARARGS) { + func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS; + } else { + goto api_error; + } + + obj = duk_hnativefunction_alloc(thr->heap, flags); + if (!obj) { + DUK_ERROR_ALLOC_DEFMSG(thr); + } + + obj->func = func; + obj->nargs = func_nargs; + + DUK_DDD(DUK_DDDPRINT("created native function object with flags: 0x%08lx, nargs=%ld", + (unsigned long) obj->obj.hdr.h_flags, (long) obj->nargs)); + + tv_slot = thr->valstack_top; + DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); + DUK_HOBJECT_INCREF(thr, obj); + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + thr->valstack_top++; + + /* default prototype (Note: 'obj' must be reachable) */ + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); + + return ret; + + api_error: + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + return 0; /* not reached */ +} + +DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_int_t nargs) { + duk_uint_t flags; + + DUK_ASSERT_CTX_VALID(ctx); + + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_NATIVEFUNCTION | + DUK_HOBJECT_FLAG_NEWENV | + DUK_HOBJECT_FLAG_STRICT | + DUK_HOBJECT_FLAG_NOTAIL | + DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); + + return duk__push_c_function_raw(ctx, func, nargs, flags); +} + +DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) { + duk_uint_t flags; + + DUK_ASSERT_CTX_VALID(ctx); + + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_NATIVEFUNCTION | + DUK_HOBJECT_FLAG_NEWENV | + DUK_HOBJECT_FLAG_STRICT | + DUK_HOBJECT_FLAG_NOTAIL | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); + + (void) duk__push_c_function_raw(ctx, func, nargs, flags); +} + +DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) { + duk_uint_t flags; + + DUK_ASSERT_CTX_VALID(ctx); + + flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_NATIVEFUNCTION | + DUK_HOBJECT_FLAG_NEWENV | + DUK_HOBJECT_FLAG_STRICT | + DUK_HOBJECT_FLAG_NOTAIL | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); + + (void) duk__push_c_function_raw(ctx, func, nargs, flags); +} + +DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval tv_tmp; + duk_small_uint_t lf_flags; + + DUK_ASSERT_CTX_VALID(ctx); + + /* check stack first */ + if (thr->valstack_top >= thr->valstack_end) { + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + } + + if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) { + /* as is */ + } else if (nargs == DUK_VARARGS) { + nargs = DUK_LFUNC_NARGS_VARARGS; + } else { + goto api_error; + } + if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) { + goto api_error; + } + if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) { + goto api_error; + } + + lf_flags = DUK_LFUNC_FLAGS_PACK(magic, length, nargs); + DUK_TVAL_SET_LIGHTFUNC(&tv_tmp, func, lf_flags); + duk_push_tval(ctx, &tv_tmp); /* XXX: direct valstack write */ + DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); + return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1; + + api_error: + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + return 0; /* not reached */ +} + +DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hbufferobject *obj; + duk_tval *tv_slot; + + DUK_ASSERT(ctx != NULL); + DUK_ASSERT(prototype_bidx >= 0); + + /* check stack first */ + if (thr->valstack_top >= thr->valstack_end) { + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + } + + obj = duk_hbufferobject_alloc(thr->heap, hobject_flags_and_class); + if (!obj) { + DUK_ERROR_ALLOC_DEFMSG(thr); + } + + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]); + DUK_ASSERT_HBUFFEROBJECT_VALID(obj); + + tv_slot = thr->valstack_top; + DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); + DUK_HOBJECT_INCREF(thr, obj); + thr->valstack_top++; + + return obj; +} + +/* XXX: There's quite a bit of overlap with buffer creation handling in + * duk_bi_buffer.c. Look for overlap and refactor. + */ +#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,isview) \ + (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (isview)) + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +static const duk_uint32_t duk__bufobj_flags_lookup[] = { + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DUKTAPE_BUFFER */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_NODEJS_BUFFER */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_DATAVIEW */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */ + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */ +}; +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +/* Only allow Duktape.Buffer when support disabled. */ +static const duk_uint32_t duk__bufobj_flags_lookup[] = { + DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0) /* DUK_BUFOBJ_DUKTAPE_BUFFER */ +}; +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ +#undef DUK__PACK_ARGS + +DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) { + duk_hthread *thr; + duk_hbufferobject *h_bufobj; + duk_hbuffer *h_val; + duk_uint32_t tmp; + duk_uint_t classnum; + duk_uint_t protobidx; + duk_uint_t lookupidx; + duk_uint_t uint_offset, uint_length, uint_added; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + /* The underlying types for offset/length in duk_hbufferobject is + * duk_uint_t; make sure argument values fit and that offset + length + * does not wrap. + */ + uint_offset = (duk_uint_t) byte_offset; + uint_length = (duk_uint_t) byte_length; + if (sizeof(duk_size_t) != sizeof(duk_uint_t)) { + if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) { + goto range_error; + } + } + uint_added = uint_offset + uint_length; + if (uint_added < uint_offset) { + goto range_error; + } + DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length); + + DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */ + lookupidx = flags & 0x0f; /* 4 low bits */ + if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) { + goto arg_error; + } + tmp = duk__bufobj_flags_lookup[lookupidx]; + classnum = tmp >> 24; + protobidx = (tmp >> 16) & 0xff; + + h_val = duk_require_hbuffer(ctx, idx_buffer); + DUK_ASSERT(h_val != NULL); + + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(classnum), + protobidx); + DUK_ASSERT(h_bufobj != NULL); + + h_bufobj->buf = h_val; + DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->offset = uint_offset; + h_bufobj->length = uint_length; + h_bufobj->shift = (tmp >> 4) & 0x0f; + h_bufobj->elem_type = (tmp >> 8) & 0xff; + h_bufobj->is_view = tmp & 0x0f; + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) + /* TypedArray views need an automatic ArrayBuffer which must be + * provided as .buffer property of the view. Just create a new + * ArrayBuffer sharing the same underlying buffer. + */ + if (flags & DUK_BUFOBJ_CREATE_ARRBUF) { + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + + DUK_ASSERT(h_bufobj != NULL); + + h_bufobj->buf = h_val; + DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->offset = uint_offset; + h_bufobj->length = uint_length; + DUK_ASSERT(h_bufobj->shift == 0); + h_bufobj->elem_type = DUK_HBUFFEROBJECT_ELEM_UINT8; + DUK_ASSERT(h_bufobj->is_view == 0); + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); + duk_compact(ctx, -1); + } +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + + return; + + range_error: + DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS); + return; /* not reached */ + + arg_error: + DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CALL_ARGS); + return; /* not reached */ +} + +DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t ret; + duk_hobject *proto; +#ifdef DUK_USE_AUGMENT_ERROR_CREATE + duk_bool_t noblame_fileline; +#endif + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_UNREF(filename); + DUK_UNREF(line); + + /* Error code also packs a tracedata related flag. */ +#ifdef DUK_USE_AUGMENT_ERROR_CREATE + noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE; +#endif + err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE); + + /* error gets its 'name' from the prototype */ + proto = duk_error_prototype_from_code(thr, err_code); + ret = duk_push_object_helper_proto(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR), + proto); + + /* ... and its 'message' from an instance property */ + if (fmt) { + duk_push_vsprintf(ctx, fmt, ap); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); + } else { + /* If no explicit message given, put error code into message field + * (as a number). This is not fully in keeping with the Ecmascript + * error model because messages are supposed to be strings (Error + * constructors use ToString() on their argument). However, it's + * probably more useful than having a separate 'code' property. + */ + duk_push_int(ctx, err_code); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); + } + + /* XXX: .code = err_code disabled, not sure if useful */ + + /* Creation time error augmentation */ +#ifdef DUK_USE_AUGMENT_ERROR_CREATE + /* filename may be NULL in which case file/line is not recorded */ + duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline); /* may throw an error */ +#endif + + return ret; +} + +DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) { + va_list ap; + duk_idx_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + va_start(ap, fmt); + ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap); + va_end(ap); + return ret; +} + +#if !defined(DUK_USE_VARIADIC_MACROS) +DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) { + const char *filename = duk_api_global_filename; + duk_int_t line = duk_api_global_line; + va_list ap; + duk_idx_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + duk_api_global_filename = NULL; + duk_api_global_line = 0; + va_start(ap, fmt); + ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap); + va_end(ap); + return ret; +} +#endif /* DUK_USE_VARIADIC_MACROS */ + +DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_slot; + duk_hbuffer *h; + void *buf_data; + + DUK_ASSERT_CTX_VALID(ctx); + + /* check stack first */ + if (thr->valstack_top >= thr->valstack_end) { + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + } + + /* Check for maximum buffer length. */ + if (size > DUK_HBUFFER_MAX_BYTELEN) { + DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); + } + + h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data); + if (!h) { + DUK_ERROR_ALLOC_DEFMSG(thr); + } + + tv_slot = thr->valstack_top; + DUK_TVAL_SET_BUFFER(tv_slot, h); + DUK_HBUFFER_INCREF(thr, h); + thr->valstack_top++; + + return (void *) buf_data; +} + +DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + + if (ptr == NULL) { + goto push_undefined; + } + + switch ((int) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { + case DUK_HTYPE_STRING: + duk_push_hstring(ctx, (duk_hstring *) ptr); + break; + case DUK_HTYPE_OBJECT: + duk_push_hobject(ctx, (duk_hobject *) ptr); + break; + case DUK_HTYPE_BUFFER: + duk_push_hbuffer(ctx, (duk_hbuffer *) ptr); + break; + default: + goto push_undefined; + } + return ret; + + push_undefined: + duk_push_undefined(ctx); + return ret; +} + +DUK_INTERNAL duk_idx_t duk_push_object_internal(duk_context *ctx) { + return duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), + -1); /* no prototype */ +} + +DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) { + duk_tval tv; + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(h != NULL); + DUK_TVAL_SET_STRING(&tv, h); + duk_push_tval(ctx, &tv); +} + +DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx) { + duk_hthread *thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS); + duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); +} + +DUK_INTERNAL void duk_push_hobject(duk_context *ctx, duk_hobject *h) { + duk_tval tv; + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(h != NULL); + DUK_TVAL_SET_OBJECT(&tv, h); + duk_push_tval(ctx, &tv); +} + +DUK_INTERNAL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h) { + duk_tval tv; + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(h != NULL); + DUK_TVAL_SET_BUFFER(&tv, h); + duk_push_tval(ctx, &tv); +} + +DUK_INTERNAL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx) { + duk_hthread *thr = (duk_hthread *) ctx; + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS); + DUK_ASSERT(thr->builtins[builtin_idx] != NULL); + duk_push_hobject(ctx, thr->builtins[builtin_idx]); +} + +/* + * Poppers + */ + +DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + + if (DUK_UNLIKELY(count < 0)) { + DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT); + return; + } + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) { + DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY); + } + + /* + * Must be very careful here, every DECREF may cause reallocation + * of our valstack. + */ + + /* XXX: inlined DECREF macro would be nice here: no NULL check, + * refzero queueing but no refzero algorithm run (= no pointer + * instability), inline code. + */ + + /* XXX: optimize loops */ + +#if defined(DUK_USE_REFERENCE_COUNTING) + while (count > 0) { + count--; + tv = --thr->valstack_top; /* tv points to element just below prev top */ + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ + } +#else + tv = thr->valstack_top; + while (count > 0) { + count--; + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED(tv); + } + thr->valstack_top = tv; +#endif + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} + +/* Popping one element is called so often that when footprint is not an issue, + * compile a specialized function for it. + */ +#if defined(DUK_USE_PREFER_SIZE) +DUK_EXTERNAL void duk_pop(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + duk_pop_n(ctx, 1); +} +#else +DUK_EXTERNAL void duk_pop(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + DUK_ASSERT_CTX_VALID(ctx); + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { + DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY); + } + + tv = --thr->valstack_top; /* tv points to element just below prev top */ + DUK_ASSERT(tv >= thr->valstack_bottom); +#ifdef DUK_USE_REFERENCE_COUNTING + DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ +#else + DUK_TVAL_SET_UNDEFINED(tv); +#endif + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} +#endif /* !DUK_USE_PREFER_SIZE */ + +DUK_EXTERNAL void duk_pop_2(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + duk_pop_n(ctx, 2); +} + +DUK_EXTERNAL void duk_pop_3(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + duk_pop_n(ctx, 3); +} + +/* + * Error throwing + */ + +DUK_EXTERNAL void duk_throw(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT(thr->valstack_bottom >= thr->valstack); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_end >= thr->valstack_top); + + if (thr->valstack_top == thr->valstack_bottom) { + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + } + + /* Errors are augmented when they are created, not when they are + * thrown or re-thrown. The current error handler, however, runs + * just before an error is thrown. + */ + + /* Sync so that augmentation sees up-to-date activations, NULL + * thr->ptr_curr_pc so that it's not used if side effects occur + * in augmentation or longjmp handling. + */ + duk_hthread_sync_and_null_currpc(thr); + +#if defined(DUK_USE_AUGMENT_ERROR_THROW) + DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(ctx, -1))); + duk_err_augment_error_throw(thr); +#endif + DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1))); + + duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); + + /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't + * need to check that here. If the value is NULL, a panic occurs because + * we can't return. + */ + + duk_err_longjmp(thr); + DUK_UNREACHABLE(); +} + +DUK_EXTERNAL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg) { + duk_hthread *thr = (duk_hthread *) ctx; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + DUK_ASSERT(thr->heap->fatal_func != NULL); + + DUK_D(DUK_DPRINT("fatal error occurred, code %ld, message %s", + (long) err_code, (const char *) err_msg)); + + /* fatal_func should be noreturn, but noreturn declarations on function + * pointers has a very spotty support apparently so it's not currently + * done. + */ + thr->heap->fatal_func(ctx, err_code, err_msg); + + DUK_PANIC(DUK_ERR_API_ERROR, "fatal handler returned"); +} + +DUK_EXTERNAL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) { + DUK_ASSERT_CTX_VALID(ctx); + + duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap); + duk_throw(ctx); +} + +DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) { + va_list ap; + + DUK_ASSERT_CTX_VALID(ctx); + + va_start(ap, fmt); + duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap); + va_end(ap); + duk_throw(ctx); +} + +#if !defined(DUK_USE_VARIADIC_MACROS) +DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) { + const char *filename; + duk_int_t line; + va_list ap; + + DUK_ASSERT_CTX_VALID(ctx); + + filename = duk_api_global_filename; + line = duk_api_global_line; + duk_api_global_filename = NULL; + duk_api_global_line = 0; + + va_start(ap, fmt); + duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap); + va_end(ap); + duk_throw(ctx); +} +#endif /* DUK_USE_VARIADIC_MACROS */ + +/* + * Comparison + */ + +DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv1, *tv2; + + DUK_ASSERT_CTX_VALID(ctx); + + tv1 = duk_get_tval(ctx, index1); + tv2 = duk_get_tval(ctx, index2); + if ((tv1 == NULL) || (tv2 == NULL)) { + return 0; + } + + /* Coercion may be needed, the helper handles that by pushing the + * tagged values to the stack. + */ + return duk_js_equals(thr, tv1, tv2); +} + +DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) { + duk_tval *tv1, *tv2; + + DUK_ASSERT_CTX_VALID(ctx); + + tv1 = duk_get_tval(ctx, index1); + tv2 = duk_get_tval(ctx, index2); + if ((tv1 == NULL) || (tv2 == NULL)) { + return 0; + } + + /* No coercions or other side effects, so safe */ + return duk_js_strict_equals(tv1, tv2); +} + +/* + * instanceof + */ + +DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) { + duk_tval *tv1, *tv2; + + DUK_ASSERT_CTX_VALID(ctx); + + /* Index validation is strict, which differs from duk_equals(). + * The strict behavior mimics how instanceof itself works, e.g. + * it is a TypeError if rval is not a -callable- object. It would + * be somewhat inconsistent if rval would be allowed to be + * non-existent without a TypeError. + */ + tv1 = duk_require_tval(ctx, index1); + DUK_ASSERT(tv1 != NULL); + tv2 = duk_require_tval(ctx, index2); + DUK_ASSERT(tv2 != NULL); + + return duk_js_instanceof((duk_hthread *) ctx, tv1, tv2); +} + +/* + * Lightfunc + */ + +DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) { + duk_c_function func; + + DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); + + /* Lightfunc name, includes Duktape/C native function pointer, which + * can often be used to locate the function from a symbol table. + * The name also includes the 16-bit duk_tval flags field because it + * includes the magic value. Because a single native function often + * provides different functionality depending on the magic value, it + * seems reasonably to include it in the name. + * + * On the other hand, a complicated name increases string table + * pressure in low memory environments (but only when function name + * is accessed). + */ + + func = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv); + duk_push_sprintf(ctx, "light_"); + duk_push_string_funcptr(ctx, (duk_uint8_t *) &func, sizeof(func)); + duk_push_sprintf(ctx, "_%04x", (unsigned int) DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv)); + duk_concat(ctx, 3); +} + +DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) { + DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); + + duk_push_string(ctx, "function "); + duk_push_lightfunc_name(ctx, tv); + duk_push_string(ctx, "() {\"light\"}"); + duk_concat(ctx, 3); +} + +/* + * Function pointers + * + * Printing function pointers is non-portable, so we do that by hex printing + * bytes from memory. + */ + +DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz) { + duk_uint8_t buf[32 * 2]; + duk_uint8_t *p, *q; + duk_small_uint_t i; + duk_small_uint_t t; + + DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */ + + p = buf; +#if defined(DUK_USE_INTEGER_LE) + q = ptr + sz; +#else + q = ptr; +#endif + for (i = 0; i < sz; i++) { +#if defined(DUK_USE_INTEGER_LE) + t = *(--q); +#else + t = *(q++); +#endif + *p++ = duk_lc_digits[t >> 4]; + *p++ = duk_lc_digits[t & 0x0f]; + } + + duk_push_lstring(ctx, (const char *) buf, sz * 2); +} + +#if !defined(DUK_USE_PARANOID_ERRORS) +/* + * Push readable string summarizing duk_tval. The operation is side effect + * free and will only throw from internal errors (e.g. out of memory). + * This is used by e.g. property access code to summarize a key/base safely, + * and is not intended to be fast (but small and safe). + */ + +#define DUK__READABLE_STRING_MAXCHARS 32 + +/* String sanitizer which escapes ASCII control characters and a few other + * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with + * question marks. No errors are thrown for any input string, except in out + * of memory situations. + */ +DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring *h_input) { + duk_hthread *thr; + const duk_uint8_t *p, *p_start, *p_end; + duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS + + 2 /*quotes*/ + 3 /*periods*/]; + duk_uint8_t *q; + duk_ucodepoint_t cp; + duk_small_uint_t nchars; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(h_input != NULL); + thr = (duk_hthread *) ctx; + + p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); + p = p_start; + q = buf; + + nchars = 0; + *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE; + for (;;) { + if (p >= p_end) { + break; + } + if (nchars == DUK__READABLE_STRING_MAXCHARS) { + *q++ = (duk_uint8_t) DUK_ASC_PERIOD; + *q++ = (duk_uint8_t) DUK_ASC_PERIOD; + *q++ = (duk_uint8_t) DUK_ASC_PERIOD; + break; + } + if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) { + if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) { + DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */ + DUK_ASSERT((cp >> 4) <= 0x0f); + *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH; + *q++ = (duk_uint8_t) DUK_ASC_LC_X; + *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4]; + *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f]; + } else { + q += duk_unicode_encode_xutf8(cp, q); + } + } else { + p++; /* advance manually */ + *q++ = (duk_uint8_t) DUK_ASC_QUESTION; + } + nchars++; + } + *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE; + + duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf)); +} + +DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) { + duk_hthread *thr; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + if (tv == NULL) { + duk_push_string(ctx, "none"); + } else { + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_STRING: { + duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv)); + break; + } + case DUK_TAG_OBJECT: { + duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + duk_push_hobject_class_string(ctx, h); + break; + } + case DUK_TAG_BUFFER: { + /* XXX: Hex encoded, length limited buffer summary here? */ + duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + duk_push_sprintf(ctx, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h)); + break; + } + case DUK_TAG_POINTER: { + /* Surround with parentheses like in JX, ensures NULL pointer + * is distinguishable from null value ("(null)" vs "null"). + */ + duk_push_tval(ctx, tv); + duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1)); + duk_remove(ctx, -2); + break; + } + default: { + duk_push_tval(ctx, tv); + break; + } + } + } + + return duk_to_string(ctx, -1); +} + +DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, index)); +} +#endif /* !DUK_USE_PARANOID_ERRORS */ + +#undef DUK__CHECK_SPACE +#undef DUK__PACK_ARGS +#undef DUK__READABLE_STRING_MAXCHARS +/* + * String manipulation + */ + +/* include removed: duk_internal.h */ + +DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_bool_t is_join) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_uint_t count; + duk_uint_t i; + duk_size_t idx; + duk_size_t len; + duk_hstring *h; + duk_uint8_t *buf; + + DUK_ASSERT_CTX_VALID(ctx); + + if (DUK_UNLIKELY(count_in <= 0)) { + if (count_in < 0) { + DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT); + return; + } + DUK_ASSERT(count_in == 0); + duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); + return; + } + count = (duk_uint_t) count_in; + + if (is_join) { + duk_size_t t1, t2, limit; + h = duk_to_hstring(ctx, -((duk_idx_t) count) - 1); + DUK_ASSERT(h != NULL); + + /* A bit tricky overflow test, see doc/code-issues.rst. */ + t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); + t2 = (duk_size_t) (count - 1); + limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN; + if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) { + /* Combined size of separators already overflows */ + goto error_overflow; + } + len = (duk_size_t) (t1 * t2); + } else { + len = (duk_size_t) 0; + } + + for (i = count; i >= 1; i--) { + duk_size_t new_len; + duk_to_string(ctx, -((duk_idx_t) i)); + h = duk_require_hstring(ctx, -((duk_idx_t) i)); + new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); + + /* Impose a string maximum length, need to handle overflow + * correctly. + */ + if (new_len < len || /* wrapped */ + new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) { + goto error_overflow; + } + len = new_len; + } + + DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes", + (unsigned long) count, (unsigned long) len)); + + /* use stack allocated buffer to ensure reachability in errors (e.g. intern error) */ + buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, len); + DUK_ASSERT(buf != NULL); + + /* [... (sep) str1 str2 ... strN buf] */ + + idx = 0; + for (i = count; i >= 1; i--) { + if (is_join && i != count) { + h = duk_require_hstring(ctx, -((duk_idx_t) count) - 2); /* extra -1 for buffer */ + DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + idx += DUK_HSTRING_GET_BYTELEN(h); + } + h = duk_require_hstring(ctx, -((duk_idx_t) i) - 1); /* extra -1 for buffer */ + DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + idx += DUK_HSTRING_GET_BYTELEN(h); + } + + DUK_ASSERT(idx == len); + + /* [... (sep) str1 str2 ... strN buf] */ + + /* get rid of the strings early to minimize memory use before intern */ + + if (is_join) { + duk_replace(ctx, -((duk_idx_t) count) - 2); /* overwrite sep */ + duk_pop_n(ctx, count); + } else { + duk_replace(ctx, -((duk_idx_t) count) - 1); /* overwrite str1 */ + duk_pop_n(ctx, count-1); + } + + /* [... buf] */ + + (void) duk_to_string(ctx, -1); + + /* [... res] */ + return; + + error_overflow: + DUK_ERROR_RANGE(thr, DUK_STR_CONCAT_RESULT_TOO_LONG); +} + +DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) { + DUK_ASSERT_CTX_VALID(ctx); + + duk__concat_and_join_helper(ctx, count, 0 /*is_join*/); +} + +DUK_EXTERNAL void duk_join(duk_context *ctx, duk_idx_t count) { + DUK_ASSERT_CTX_VALID(ctx); + + duk__concat_and_join_helper(ctx, count, 1 /*is_join*/); +} + +/* XXX: could map/decode be unified with duk_unicode_support.c code? + * Case conversion needs also the character surroundings though. + */ + +DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hstring *h_input; + const duk_uint8_t *p, *p_start, *p_end; + duk_codepoint_t cp; + + DUK_ASSERT_CTX_VALID(ctx); + + h_input = duk_require_hstring(ctx, index); + DUK_ASSERT(h_input != NULL); + + p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); + p = p_start; + + for (;;) { + if (p >= p_end) { + break; + } + cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); + callback(udata, cp); + } +} + +DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hstring *h_input; + duk_bufwriter_ctx bw_alloc; + duk_bufwriter_ctx *bw; + const duk_uint8_t *p, *p_start, *p_end; + duk_codepoint_t cp; + + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_normalize_index(ctx, index); + + h_input = duk_require_hstring(ctx, index); + DUK_ASSERT(h_input != NULL); + + bw = &bw_alloc; + DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* reasonable output estimate */ + + p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); + p = p_start; + + for (;;) { + /* XXX: could write output in chunks with fewer ensure calls, + * but relative benefit would be small here. + */ + + if (p >= p_end) { + break; + } + cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); + cp = callback(udata, cp); + + DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp); + } + + DUK_BW_COMPACT(thr, bw); + duk_to_string(ctx, -1); + duk_replace(ctx, index); +} + +DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_offset, duk_size_t end_offset) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hstring *h; + duk_hstring *res; + duk_size_t start_byte_offset; + duk_size_t end_byte_offset; + + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_require_normalize_index(ctx, index); + h = duk_require_hstring(ctx, index); + DUK_ASSERT(h != NULL); + + if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) { + end_offset = DUK_HSTRING_GET_CHARLEN(h); + } + if (start_offset > end_offset) { + start_offset = end_offset; + } + + DUK_ASSERT_DISABLE(start_offset >= 0); + DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h)); + DUK_ASSERT_DISABLE(end_offset >= 0); + DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h)); + + /* guaranteed by string limits */ + DUK_ASSERT(start_offset <= DUK_UINT32_MAX); + DUK_ASSERT(end_offset <= DUK_UINT32_MAX); + + start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset); + end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset); + + DUK_ASSERT(end_byte_offset >= start_byte_offset); + DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* guaranteed by string limits */ + + /* no size check is necessary */ + res = duk_heap_string_intern_checked(thr, + DUK_HSTRING_GET_DATA(h) + start_byte_offset, + (duk_uint32_t) (end_byte_offset - start_byte_offset)); + + duk_push_hstring(ctx, res); + duk_replace(ctx, index); +} + +/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and + * forwards with a callback to process codepoints? + */ +DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hstring *h; + const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */ + const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */ + duk_codepoint_t cp; + + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_require_normalize_index(ctx, index); + h = duk_require_hstring(ctx, index); + DUK_ASSERT(h != NULL); + + p_start = DUK_HSTRING_GET_DATA(h); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h); + + p = p_start; + while (p < p_end) { + p_tmp1 = p; + cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end); + if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) { + break; + } + p = p_tmp1; + } + q_start = p; + if (p == p_end) { + /* entire string is whitespace */ + q_end = p; + goto scan_done; + } + + p = p_end; + while (p > p_start) { + p_tmp1 = p; + while (p > p_start) { + p--; + if (((*p) & 0xc0) != 0x80) { + break; + } + } + p_tmp2 = p; + + cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end); + if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) { + p = p_tmp1; + break; + } + } + q_end = p; + + scan_done: + /* This may happen when forward and backward scanning disagree + * (possible for non-extended-UTF-8 strings). + */ + if (q_end < q_start) { + q_end = q_start; + } + + DUK_ASSERT(q_start >= p_start && q_start <= p_end); + DUK_ASSERT(q_end >= p_start && q_end <= p_end); + DUK_ASSERT(q_end >= q_start); + + DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p", + (const void *) p_start, (const void *) p_end, + (const void *) q_start, (const void *) q_end)); + + if (q_start == p_start && q_end == p_end) { + DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)")); + return; + } + + duk_push_lstring(ctx, (const char *) q_start, (duk_size_t) (q_end - q_start)); + duk_replace(ctx, index); +} + +DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hstring *h; + duk_ucodepoint_t cp; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_require_hstring(ctx, index); + DUK_ASSERT(h != NULL); + + DUK_ASSERT_DISABLE(char_offset >= 0); /* always true, arg is unsigned */ + if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) { + return 0; + } + + DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* guaranteed by string limits */ + cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset); + return (duk_codepoint_t) cp; +} +/* + * Variable access + */ + +/* include removed: duk_internal.h */ + +DUK_EXTERNAL void duk_get_var(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + duk_hstring *h_varname; + duk_small_int_t throw_flag = 1; /* always throw ReferenceError for unresolvable */ + + DUK_ASSERT_CTX_VALID(ctx); + + h_varname = duk_require_hstring(ctx, -1); /* XXX: tostring? */ + DUK_ASSERT(h_varname != NULL); + + act = duk_hthread_get_current_activation(thr); + if (act) { + (void) duk_js_getvar_activation(thr, act, h_varname, throw_flag); /* -> [ ... varname val this ] */ + } else { + /* Outside any activation -> look up from global. */ + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); + (void) duk_js_getvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, throw_flag); + } + + /* [ ... varname val this ] (because throw_flag == 1, always resolved) */ + + duk_pop(ctx); + duk_remove(ctx, -2); + + /* [ ... val ] */ + + /* Return value would be pointless: because throw_flag==1, we always + * throw if the identifier doesn't resolve. + */ + return; +} + +DUK_EXTERNAL void duk_put_var(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + duk_hstring *h_varname; + duk_tval *tv_val; + duk_small_int_t throw_flag; + + DUK_ASSERT_CTX_VALID(ctx); + + h_varname = duk_require_hstring(ctx, -2); /* XXX: tostring? */ + DUK_ASSERT(h_varname != NULL); + + tv_val = duk_require_tval(ctx, -1); + + throw_flag = duk_is_strict_call(ctx); + + act = duk_hthread_get_current_activation(thr); + if (act) { + duk_js_putvar_activation(thr, act, h_varname, tv_val, throw_flag); /* -> [ ... varname val this ] */ + } else { + /* Outside any activation -> put to global. */ + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); + duk_js_putvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, tv_val, throw_flag); + } + + /* [ ... varname val ] */ + + duk_pop_2(ctx); + + /* [ ... ] */ + + return; +} + +DUK_EXTERNAL duk_bool_t duk_del_var(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + + DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx); + return 0; +} + +DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) { + DUK_ASSERT_CTX_VALID(ctx); + + DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx); + return 0; +} +/* + * Array built-ins + * + * Note that most Array built-ins are intentionally generic and work even + * when the 'this' binding is not an Array instance. To ensure this, + * Array algorithms do not assume "magical" Array behavior for the "length" + * property, for instance. + * + * XXX: the "Throw" flag should be set for (almost?) all [[Put]] and + * [[Delete]] operations, but it's currently false throughout. Go through + * all put/delete cases and check throw flag use. Need a new API primitive + * which allows throws flag to be specified. + * + * XXX: array lengths above 2G won't work reliably. There are many places + * where one needs a full signed 32-bit range ([-0xffffffff, 0xffffffff], + * i.e. -33- bits). Although array 'length' cannot be written to be outside + * the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so) + * some intermediate values may be above 0xffffffff and this may not be always + * correctly handled now (duk_uint32_t is not enough for all algorithms). + * + * For instance, push() can legitimately write entries beyond length 0xffffffff + * and cause a RangeError only at the end. To do this properly, the current + * push() implementation tracks the array index using a 'double' instead of a + * duk_uint32_t (which is somewhat awkward). See test-bi-array-push-maxlen.js. + * + * On using "put" vs. "def" prop + * ============================= + * + * Code below must be careful to use the appropriate primitive as it matters + * for compliance. When using "put" there may be inherited properties in + * Array.prototype which cause side effects when values are written. When + * using "define" there are no such side effects, and many test262 test cases + * check for this (for real world code, such side effects are very rare). + * Both "put" and "define" are used in the E5.1 specification; as a rule, + * "put" is used when modifying an existing array (or a non-array 'this' + * binding) and "define" for setting values into a fresh result array. + * + * Also note that Array instance 'length' should be writable, but not + * enumerable and definitely not configurable: even Duktape code internally + * assumes that an Array instance will always have a 'length' property. + * Preventing deletion of the property is critical. + */ + +/* include removed: duk_internal.h */ + +/* Perform an intermediate join when this many elements have been pushed + * on the value stack. + */ +#define DUK__ARRAY_MID_JOIN_LIMIT 4096 + +/* Shared entry code for many Array built-ins. Note that length is left + * on stack (it could be popped, but that's not necessary). + */ +DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_context *ctx) { + duk_uint32_t len; + + (void) duk_push_this_coercible_to_object(ctx); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH); + len = duk_to_uint32(ctx, -1); + + /* -> [ ... ToObject(this) ToUint32(length) ] */ + return len; +} + +DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) { + /* Range limited to [0, 0x7fffffff] range, i.e. range that can be + * represented with duk_int32_t. Use this when the method doesn't + * handle the full 32-bit unsigned range correctly. + */ + duk_uint32_t ret = duk__push_this_obj_len_u32(ctx); + if (DUK_UNLIKELY(ret >= 0x80000000UL)) { + DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_ARRAY_LENGTH_OVER_2G); + } + return ret; +} + +/* + * Constructor + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) { + duk_idx_t nargs; + duk_double_t d; + duk_uint32_t len; + duk_idx_t i; + + nargs = duk_get_top(ctx); + duk_push_array(ctx); + + if (nargs == 1 && duk_is_number(ctx, 0)) { + /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */ + d = duk_get_number(ctx, 0); + len = duk_to_uint32(ctx, 0); + if (((duk_double_t) len) != d) { + return DUK_RET_RANGE_ERROR; + } + + /* XXX: if 'len' is low, may want to ensure array part is kept: + * the caller is likely to want a dense array. + */ + duk_push_u32(ctx, len); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); /* [ ToUint32(len) array ToUint32(len) ] -> [ ToUint32(len) array ] */ + return 1; + } + + /* XXX: optimize by creating array into correct size directly, and + * operating on the array part directly; values can be memcpy()'d from + * value stack directly as long as refcounts are increased. + */ + for (i = 0; i < nargs; i++) { + duk_dup(ctx, i); + duk_xdef_prop_index_wec(ctx, -2, (duk_uarridx_t) i); + } + + duk_push_u32(ctx, (duk_uint32_t) nargs); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + return 1; +} + +/* + * isArray() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) { + duk_hobject *h; + + h = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_ARRAY); + duk_push_boolean(ctx, (h != NULL)); + return 1; +} + +/* + * toString() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) { + (void) duk_push_this_coercible_to_object(ctx); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN); + + /* [ ... this func ] */ + if (!duk_is_callable(ctx, -1)) { + /* Fall back to the initial (original) Object.toString(). We don't + * currently have pointers to the built-in functions, only the top + * level global objects (like "Array") so this is now done in a bit + * of a hacky manner. It would be cleaner to push the (original) + * function and use duk_call_method(). + */ + + /* XXX: 'this' will be ToObject() coerced twice, which is incorrect + * but should have no visible side effects. + */ + DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString")); + duk_set_top(ctx, 0); + return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */ + } + + /* [ ... this func ] */ + + duk_insert(ctx, -2); + + /* [ ... func this ] */ + + DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT", + (duk_tval *) duk_get_tval(ctx, -2), + (duk_tval *) duk_get_tval(ctx, -1))); + duk_call_method(ctx, 0); + + return 1; +} + +/* + * concat() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) { + duk_idx_t i, n; + duk_uarridx_t idx, idx_last; + duk_uarridx_t j, len; + duk_hobject *h; + + /* XXX: the insert here is a bit expensive if there are a lot of items. + * It could also be special cased in the outermost for loop quite easily + * (as the element is dup()'d anyway). + */ + + (void) duk_push_this_coercible_to_object(ctx); + duk_insert(ctx, 0); + n = duk_get_top(ctx); + duk_push_array(ctx); /* -> [ ToObject(this) item1 ... itemN arr ] */ + + /* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index() + * (which differs from the official algorithm). If no error is thrown, this + * doesn't matter as the length is updated at the end. However, if an error + * is thrown, the length will be unset. That shouldn't matter because the + * caller won't get a reference to the intermediate value. + */ + + idx = 0; + idx_last = 0; + for (i = 0; i < n; i++) { + DUK_ASSERT_TOP(ctx, n + 1); + + /* [ ToObject(this) item1 ... itemN arr ] */ + + duk_dup(ctx, i); + h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY); + if (!h) { + duk_xdef_prop_index_wec(ctx, -2, idx++); + idx_last = idx; + continue; + } + + /* [ ToObject(this) item1 ... itemN arr item(i) ] */ + + /* XXX: an array can have length higher than 32 bits; this is not handled + * correctly now. + */ + len = (duk_uarridx_t) duk_get_length(ctx, -1); + for (j = 0; j < len; j++) { + if (duk_get_prop_index(ctx, -1, j)) { + /* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */ + duk_xdef_prop_index_wec(ctx, -3, idx++); + idx_last = idx; + } else { + idx++; + duk_pop(ctx); +#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER) + /* According to E5.1 Section 15.4.4.4 nonexistent trailing + * elements do not affect 'length' of the result. Test262 + * and other engines disagree, so update idx_last here too. + */ + idx_last = idx; +#else + /* Strict standard behavior, ignore trailing elements for + * result 'length'. + */ +#endif + } + } + duk_pop(ctx); + } + + /* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly + * in the end, but because we're operating with an internal value which + * is known to be an array, this should be equivalent. + */ + duk_push_uarridx(ctx, idx_last); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + + DUK_ASSERT_TOP(ctx, n + 1); + return 1; +} + +/* + * join(), toLocaleString() + * + * Note: checking valstack is necessary, but only in the per-element loop. + * + * Note: the trivial approach of pushing all the elements on the value stack + * and then calling duk_join() fails when the array contains a large number + * of elements. This problem can't be offloaded to duk_join() because the + * elements to join must be handled here and have special handling. Current + * approach is to do intermediate joins with very large number of elements. + * There is no fancy handling; the prefix gets re-joined multiple times. + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) { + duk_uint32_t len, count; + duk_uint32_t idx; + duk_small_int_t to_locale_string = duk_get_current_magic(ctx); + duk_idx_t valstack_required; + + /* For join(), nargs is 1. For toLocaleString(), nargs is 0 and + * setting the top essentially pushes an undefined to the stack, + * thus defaulting to a comma separator. + */ + duk_set_top(ctx, 1); + if (duk_is_undefined(ctx, 0)) { + duk_pop(ctx); + duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA); + } else { + duk_to_string(ctx, 0); + } + + len = duk__push_this_obj_len_u32(ctx); + + /* [ sep ToObject(this) len ] */ + + DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu", + (duk_tval *) duk_get_tval(ctx, 0), + (duk_tval *) duk_get_tval(ctx, 1), + (unsigned long) len)); + + /* The extra (+4) is tight. */ + valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ? + DUK__ARRAY_MID_JOIN_LIMIT : len) + 4; + duk_require_stack(ctx, valstack_required); + + duk_dup(ctx, 0); + + /* [ sep ToObject(this) len sep ] */ + + count = 0; + idx = 0; + for (;;) { + if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */ + idx >= len) { /* end of loop (careful with len==0) */ + /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */ + DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld", + (long) count, (long) idx, (long) len)); + duk_join(ctx, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */ + duk_dup(ctx, 0); /* -> [ sep ToObject(this) len str sep ] */ + duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */ + count = 1; + } + if (idx >= len) { + /* if true, the stack already contains the final result */ + break; + } + + duk_get_prop_index(ctx, 1, (duk_uarridx_t) idx); + if (duk_is_null_or_undefined(ctx, -1)) { + duk_pop(ctx); + duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); + } else { + if (to_locale_string) { + duk_to_object(ctx, -1); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING); + duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */ + duk_call_method(ctx, 0); + duk_to_string(ctx, -1); + } else { + duk_to_string(ctx, -1); + } + } + + count++; + idx++; + } + + /* [ sep ToObject(this) len sep result ] */ + + return 1; +} + +/* + * pop(), push() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) { + duk_uint32_t len; + duk_uint32_t idx; + + DUK_ASSERT_TOP(ctx, 0); + len = duk__push_this_obj_len_u32(ctx); + if (len == 0) { + duk_push_int(ctx, 0); + duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); + return 0; + } + idx = len - 1; + + duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx); + duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx); + duk_push_u32(ctx, idx); + duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) { + /* Note: 'this' is not necessarily an Array object. The push() + * algorithm is supposed to work for other kinds of objects too, + * so the algorithm has e.g. an explicit update for the 'length' + * property which is normally "magical" in arrays. + */ + + duk_uint32_t len; + duk_idx_t i, n; + + n = duk_get_top(ctx); + len = duk__push_this_obj_len_u32(ctx); + + /* [ arg1 ... argN obj length ] */ + + /* Technically Array.prototype.push() can create an Array with length + * longer than 2^32-1, i.e. outside the 32-bit range. The final length + * is *not* wrapped to 32 bits in the specification. + * + * This implementation tracks length with a uint32 because it's much + * more practical. + * + * See: test-bi-array-push-maxlen.js. + */ + + if (len + (duk_uint32_t) n < len) { + DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw")); + return DUK_RET_RANGE_ERROR; + } + + for (i = 0; i < n; i++) { + duk_dup(ctx, i); + duk_put_prop_index(ctx, -3, len + i); + } + len += n; + + duk_push_u32(ctx, len); + duk_dup_top(ctx); + duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH); + + /* [ arg1 ... argN obj length new_length ] */ + return 1; +} + +/* + * sort() + * + * Currently qsort with random pivot. This is now really, really slow, + * because there is no fast path for array parts. + * + * Signed indices are used because qsort() leaves and degenerate cases + * may use a negative offset. + */ + +DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t idx1, duk_int_t idx2) { + duk_bool_t have1, have2; + duk_bool_t undef1, undef2; + duk_small_int_t ret; + duk_idx_t idx_obj = 1; /* fixed offsets in valstack */ + duk_idx_t idx_fn = 0; + duk_hstring *h1, *h2; + + /* Fast exit if indices are identical. This is valid for a non-existent property, + * for an undefined value, and almost always for ToString() coerced comparison of + * arbitrary values (corner cases where this is not the case include e.g. a an + * object with varying ToString() coercion). + * + * The specification does not prohibit "caching" of values read from the array, so + * assuming equality for comparing an index with itself falls into the category of + * "caching". + * + * Also, compareFn may be inconsistent, so skipping a call to compareFn here may + * have an effect on the final result. The specification does not require any + * specific behavior for inconsistent compare functions, so again, this fast path + * is OK. + */ + + if (idx1 == idx2) { + DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld -> indices identical, quick exit", + (long) idx1, (long) idx2)); + return 0; + } + + have1 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx1); + have2 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx2); + + DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T", + (long) idx1, (long) idx2, (long) have1, (long) have2, + (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); + + if (have1) { + if (have2) { + ; + } else { + ret = -1; + goto pop_ret; + } + } else { + if (have2) { + ret = 1; + goto pop_ret; + } else { + ret = 0; + goto pop_ret; + } + } + + undef1 = duk_is_undefined(ctx, -2); + undef2 = duk_is_undefined(ctx, -1); + if (undef1) { + if (undef2) { + ret = 0; + goto pop_ret; + } else { + ret = 1; + goto pop_ret; + } + } else { + if (undef2) { + ret = -1; + goto pop_ret; + } else { + ; + } + } + + if (!duk_is_undefined(ctx, idx_fn)) { + duk_double_t d; + + /* no need to check callable; duk_call() will do that */ + duk_dup(ctx, idx_fn); /* -> [ ... x y fn ] */ + duk_insert(ctx, -3); /* -> [ ... fn x y ] */ + duk_call(ctx, 2); /* -> [ ... res ] */ + + /* The specification is a bit vague what to do if the return + * value is not a number. Other implementations seem to + * tolerate non-numbers but e.g. V8 won't apparently do a + * ToNumber(). + */ + + /* XXX: best behavior for real world compatibility? */ + + d = duk_to_number(ctx, -1); + if (d < 0.0) { + ret = -1; + } else if (d > 0.0) { + ret = 1; + } else { + ret = 0; + } + + duk_pop(ctx); + DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret)); + return ret; + } + + /* string compare is the default (a bit oddly) */ + + h1 = duk_to_hstring(ctx, -2); + h2 = duk_to_hstring(ctx, -1); + DUK_ASSERT(h1 != NULL); + DUK_ASSERT(h2 != NULL); + + ret = duk_js_string_compare(h1, h2); /* retval is directly usable */ + goto pop_ret; + + pop_ret: + duk_pop_2(ctx); + DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret)); + return ret; +} + +DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r) { + duk_bool_t have_l, have_r; + duk_idx_t idx_obj = 1; /* fixed offset in valstack */ + + if (l == r) { + return; + } + + /* swap elements; deal with non-existent elements correctly */ + have_l = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) l); + have_r = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) r); + + if (have_r) { + /* right exists, [[Put]] regardless whether or not left exists */ + duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) l); + } else { + duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) l); + duk_pop(ctx); + } + + if (have_l) { + duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) r); + } else { + duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) r); + duk_pop(ctx); + } +} + +#if defined(DUK_USE_DDDPRINT) +/* Debug print which visualizes the qsort partitioning process. */ +DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int_t hi, duk_int_t pivot) { + char buf[4096]; + char *ptr = buf; + duk_int_t i, n; + n = (duk_int_t) duk_get_length(ctx, 1); + if (n > 4000) { + n = 4000; + } + *ptr++ = '['; + for (i = 0; i < n; i++) { + if (i == pivot) { + *ptr++ = '|'; + } else if (i == lo) { + *ptr++ = '<'; + } else if (i == hi) { + *ptr++ = '>'; + } else if (i >= lo && i <= hi) { + *ptr++ = '-'; + } else { + *ptr++ = ' '; + } + } + *ptr++ = ']'; + *ptr++ = '\0'; + + DUK_DDD(DUK_DDDPRINT("%s (lo=%ld, hi=%ld, pivot=%ld)", + (const char *) buf, (long) lo, (long) hi, (long) pivot)); +} +#endif + +DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_int_t p, l, r; + + /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */ + + DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T", + (long) lo, (long) hi, (duk_tval *) duk_get_tval(ctx, 1))); + + DUK_ASSERT_TOP(ctx, 3); + + /* In some cases it may be that lo > hi, or hi < 0; these + * degenerate cases happen e.g. for empty arrays, and in + * recursion leaves. + */ + + /* trivial cases */ + if (hi - lo < 1) { + DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately")); + return; + } + DUK_ASSERT(hi > lo); + DUK_ASSERT(hi - lo + 1 >= 2); + + /* randomized pivot selection */ + p = lo + (duk_util_tinyrandom_get_bits(thr, 30) % (hi - lo + 1)); /* rnd in [lo,hi] */ + DUK_ASSERT(p >= lo && p <= hi); + DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", + (long) lo, (long) hi, (long) p)); + + /* move pivot out of the way */ + duk__array_sort_swap(ctx, p, lo); + p = lo; + DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(ctx, 1))); + + l = lo + 1; + r = hi; + for (;;) { + /* find elements to swap */ + for (;;) { + DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld", + (long) l, (long) r, (long) p)); + if (l >= hi) { + break; + } + if (duk__array_sort_compare(ctx, l, p) >= 0) { /* !(l < p) */ + break; + } + l++; + } + for (;;) { + DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld", + (long) l, (long) r, (long) p)); + if (r <= lo) { + break; + } + if (duk__array_sort_compare(ctx, p, r) >= 0) { /* !(p < r) */ + break; + } + r--; + } + if (l >= r) { + goto done; + } + DUK_ASSERT(l < r); + + DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r)); + + duk__array_sort_swap(ctx, l, r); + + DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(ctx, 1))); + l++; + r--; + } + done: + /* Note that 'l' and 'r' may cross, i.e. r < l */ + DUK_ASSERT(l >= lo && l <= hi); + DUK_ASSERT(r >= lo && r <= hi); + + /* XXX: there's no explicit recursion bound here now. For the average + * qsort recursion depth O(log n) that's not really necessary: e.g. for + * 2**32 recursion depth would be about 32 which is OK. However, qsort + * worst case recursion depth is O(n) which may be a problem. + */ + + /* move pivot to its final place */ + DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1))); + duk__array_sort_swap(ctx, lo, r); + +#if defined(DUK_USE_DDDPRINT) + duk__debuglog_qsort_state(ctx, lo, hi, r); +#endif + + DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(ctx, 1))); + duk__array_qsort(ctx, lo, r - 1); + duk__array_qsort(ctx, r + 1, hi); +} + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) { + duk_uint32_t len; + + /* XXX: len >= 0x80000000 won't work below because a signed type + * is needed by qsort. + */ + len = duk__push_this_obj_len_u32_limited(ctx); + + /* stack[0] = compareFn + * stack[1] = ToObject(this) + * stack[2] = ToUint32(length) + */ + + if (len > 0) { + /* avoid degenerate cases, so that (len - 1) won't underflow */ + duk__array_qsort(ctx, (duk_int_t) 0, (duk_int_t) (len - 1)); + } + + DUK_ASSERT_TOP(ctx, 3); + duk_pop(ctx); + return 1; /* return ToObject(this) */ +} + +/* + * splice() + */ + +/* XXX: this compiles to over 500 bytes now, even without special handling + * for an array part. Uses signed ints so does not handle full array range correctly. + */ + +/* XXX: can shift() / unshift() use the same helper? + * shift() is (close to?) <--> splice(0, 1) + * unshift is (close to?) <--> splice(0, 0, [items])? + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) { + duk_idx_t nargs; + duk_uint32_t len; + duk_bool_t have_delcount; + duk_int_t item_count; + duk_int_t act_start; + duk_int_t del_count; + duk_int_t i, n; + + DUK_UNREF(have_delcount); + + nargs = duk_get_top(ctx); + if (nargs < 2) { + duk_set_top(ctx, 2); + nargs = 2; + have_delcount = 0; + } else { + have_delcount = 1; + } + + /* XXX: len >= 0x80000000 won't work below because we need to be + * able to represent -len. + */ + len = duk__push_this_obj_len_u32_limited(ctx); + + act_start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len); + if (act_start < 0) { + act_start = len + act_start; + } + DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len); + +#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT + if (have_delcount) { +#endif + del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start); +#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT + } else { + /* E5.1 standard behavior when deleteCount is not given would be + * to treat it just like if 'undefined' was given, which coerces + * ultimately to 0. Real world behavior is to splice to the end + * of array, see test-bi-array-proto-splice-no-delcount.js. + */ + del_count = len - act_start; + } +#endif + + DUK_ASSERT(nargs >= 2); + item_count = (duk_int_t) (nargs - 2); + + DUK_ASSERT(del_count >= 0 && del_count <= (duk_int_t) len - act_start); + DUK_ASSERT(del_count + act_start <= (duk_int_t) len); + + /* For now, restrict result array into 32-bit length range. */ + if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) { + DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw")); + return DUK_RET_RANGE_ERROR; + } + + duk_push_array(ctx); + + /* stack[0] = start + * stack[1] = deleteCount + * stack[2...nargs-1] = items + * stack[nargs] = ToObject(this) -3 + * stack[nargs+1] = ToUint32(length) -2 + * stack[nargs+2] = result array -1 + */ + + DUK_ASSERT_TOP(ctx, nargs + 3); + + /* Step 9: copy elements-to-be-deleted into the result array */ + + for (i = 0; i < del_count; i++) { + if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (act_start + i))) { + duk_xdef_prop_index_wec(ctx, -2, i); /* throw flag irrelevant (false in std alg) */ + } else { + duk_pop(ctx); + } + } + duk_push_u32(ctx, (duk_uint32_t) del_count); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + + /* Steps 12 and 13: reorganize elements to make room for itemCount elements */ + + if (item_count < del_count) { + /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1 + * -> [ A B F G H ] (conceptual intermediate step) + * -> [ A B . F G H ] (placeholder marked) + * [ A B C F G H ] (actual result at this point, C will be replaced) + */ + + DUK_ASSERT_TOP(ctx, nargs + 3); + + n = len - del_count; + for (i = act_start; i < n; i++) { + if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) { + duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count)); + } else { + duk_pop(ctx); + duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count)); + } + } + + DUK_ASSERT_TOP(ctx, nargs + 3); + + /* loop iterator init and limit changed from standard algorithm */ + n = len - del_count + item_count; + for (i = len - 1; i >= n; i--) { + duk_del_prop_index(ctx, -3, (duk_uarridx_t) i); + } + + DUK_ASSERT_TOP(ctx, nargs + 3); + } else if (item_count > del_count) { + /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4 + * -> [ A B F G H ] (conceptual intermediate step) + * -> [ A B . . . . F G H ] (placeholder marked) + * [ A B C D E F F G H ] (actual result at this point) + */ + + DUK_ASSERT_TOP(ctx, nargs + 3); + + /* loop iterator init and limit changed from standard algorithm */ + for (i = len - del_count - 1; i >= act_start; i--) { + if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) { + duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count)); + } else { + duk_pop(ctx); + duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count)); + } + } + + DUK_ASSERT_TOP(ctx, nargs + 3); + } else { + /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3 + * -> [ A B F G H ] (conceptual intermediate step) + * -> [ A B . . . F G H ] (placeholder marked) + * [ A B C D E F G H ] (actual result at this point) + */ + } + DUK_ASSERT_TOP(ctx, nargs + 3); + + /* Step 15: insert itemCount elements into the hole made above */ + + for (i = 0; i < item_count; i++) { + duk_dup(ctx, i + 2); /* args start at index 2 */ + duk_put_prop_index(ctx, -4, (duk_uarridx_t) (act_start + i)); + } + + /* Step 16: update length; note that the final length may be above 32 bit range + * (but we checked above that this isn't the case here) + */ + + duk_push_u32(ctx, len - del_count + item_count); + duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH); + + /* result array is already at the top of stack */ + DUK_ASSERT_TOP(ctx, nargs + 3); + return 1; +} + +/* + * reverse() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) { + duk_uint32_t len; + duk_uint32_t middle; + duk_uint32_t lower, upper; + duk_bool_t have_lower, have_upper; + + len = duk__push_this_obj_len_u32(ctx); + middle = len / 2; + + /* If len <= 1, middle will be 0 and for-loop bails out + * immediately (0 < 0 -> false). + */ + + for (lower = 0; lower < middle; lower++) { + DUK_ASSERT(len >= 2); + DUK_ASSERT_TOP(ctx, 2); + + DUK_ASSERT(len >= lower + 1); + upper = len - lower - 1; + + have_lower = duk_get_prop_index(ctx, -2, (duk_uarridx_t) lower); + have_upper = duk_get_prop_index(ctx, -3, (duk_uarridx_t) upper); + + /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */ + + if (have_upper) { + duk_put_prop_index(ctx, -4, (duk_uarridx_t) lower); + } else { + duk_del_prop_index(ctx, -4, (duk_uarridx_t) lower); + duk_pop(ctx); + } + + if (have_lower) { + duk_put_prop_index(ctx, -3, (duk_uarridx_t) upper); + } else { + duk_del_prop_index(ctx, -3, (duk_uarridx_t) upper); + duk_pop(ctx); + } + + DUK_ASSERT_TOP(ctx, 2); + } + + DUK_ASSERT_TOP(ctx, 2); + duk_pop(ctx); /* -> [ ToObject(this) ] */ + return 1; +} + +/* + * slice() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) { + duk_uint32_t len; + duk_int_t start, end; + duk_int_t i; + duk_uarridx_t idx; + duk_uint32_t res_length = 0; + + /* XXX: len >= 0x80000000 won't work below because we need to be + * able to represent -len. + */ + len = duk__push_this_obj_len_u32_limited(ctx); + duk_push_array(ctx); + + /* stack[0] = start + * stack[1] = end + * stack[2] = ToObject(this) + * stack[3] = ToUint32(length) + * stack[4] = result array + */ + + start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len); + if (start < 0) { + start = len + start; + } + /* XXX: could duk_is_undefined() provide defaulting undefined to 'len' + * (the upper limit)? + */ + if (duk_is_undefined(ctx, 1)) { + end = len; + } else { + end = duk_to_int_clamped(ctx, 1, -((duk_int_t) len), (duk_int_t) len); + if (end < 0) { + end = len + end; + } + } + DUK_ASSERT(start >= 0 && (duk_uint32_t) start <= len); + DUK_ASSERT(end >= 0 && (duk_uint32_t) end <= len); + + idx = 0; + for (i = start; i < end; i++) { + DUK_ASSERT_TOP(ctx, 5); + if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) { + duk_xdef_prop_index_wec(ctx, 4, idx); + res_length = idx + 1; + } else { + duk_pop(ctx); + } + idx++; + DUK_ASSERT_TOP(ctx, 5); + } + + duk_push_u32(ctx, res_length); + duk_xdef_prop_stridx(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + + DUK_ASSERT_TOP(ctx, 5); + return 1; +} + +/* + * shift() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) { + duk_uint32_t len; + duk_uint32_t i; + + len = duk__push_this_obj_len_u32(ctx); + if (len == 0) { + duk_push_int(ctx, 0); + duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); + return 0; + } + + duk_get_prop_index(ctx, 0, 0); + + /* stack[0] = object (this) + * stack[1] = ToUint32(length) + * stack[2] = elem at index 0 (retval) + */ + + for (i = 1; i < len; i++) { + DUK_ASSERT_TOP(ctx, 3); + if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) { + /* fromPresent = true */ + duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1)); + } else { + /* fromPresent = false */ + duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1)); + duk_pop(ctx); + } + } + duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1)); + + duk_push_u32(ctx, (duk_uint32_t) (len - 1)); + duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); + + DUK_ASSERT_TOP(ctx, 3); + return 1; +} + +/* + * unshift() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) { + duk_idx_t nargs; + duk_uint32_t len; + duk_uint32_t i; + + nargs = duk_get_top(ctx); + len = duk__push_this_obj_len_u32(ctx); + + /* stack[0...nargs-1] = unshift args (vararg) + * stack[nargs] = ToObject(this) + * stack[nargs+1] = ToUint32(length) + */ + + DUK_ASSERT_TOP(ctx, nargs + 2); + + /* Note: unshift() may operate on indices above unsigned 32-bit range + * and the final length may be >= 2**32. However, we restrict the + * final result to 32-bit range for practicality. + */ + + if (len + (duk_uint32_t) nargs < len) { + DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw")); + return DUK_RET_RANGE_ERROR; + } + + i = len; + while (i > 0) { + DUK_ASSERT_TOP(ctx, nargs + 2); + i--; + /* k+argCount-1; note that may be above 32-bit range */ + + if (duk_get_prop_index(ctx, -2, (duk_uarridx_t) i)) { + /* fromPresent = true */ + /* [ ... ToObject(this) ToUint32(length) val ] */ + duk_put_prop_index(ctx, -3, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */ + } else { + /* fromPresent = false */ + /* [ ... ToObject(this) ToUint32(length) val ] */ + duk_pop(ctx); + duk_del_prop_index(ctx, -2, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */ + } + DUK_ASSERT_TOP(ctx, nargs + 2); + } + + for (i = 0; i < (duk_uint32_t) nargs; i++) { + DUK_ASSERT_TOP(ctx, nargs + 2); + duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */ + duk_put_prop_index(ctx, -3, (duk_uarridx_t) i); + DUK_ASSERT_TOP(ctx, nargs + 2); + } + + DUK_ASSERT_TOP(ctx, nargs + 2); + duk_push_u32(ctx, len + nargs); + duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */ + duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH); + return 1; +} + +/* + * indexOf(), lastIndexOf() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) { + duk_idx_t nargs; + duk_int_t i, len; + duk_int_t from_index; + duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */ + + /* lastIndexOf() needs to be a vararg function because we must distinguish + * between an undefined fromIndex and a "not given" fromIndex; indexOf() is + * made vararg for symmetry although it doesn't strictly need to be. + */ + + nargs = duk_get_top(ctx); + duk_set_top(ctx, 2); + + /* XXX: must be able to represent -len */ + len = (duk_int_t) duk__push_this_obj_len_u32_limited(ctx); + if (len == 0) { + goto not_found; + } + + /* Index clamping is a bit tricky, we must ensure that we'll only iterate + * through elements that exist and that the specific requirements from E5.1 + * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially: + * + * - indexOf: clamp to [-len,len], negative handling -> [0,len], + * if clamped result is len, for-loop bails out immediately + * + * - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1], + * if clamped result is -1, for-loop bails out immediately + * + * If fromIndex is not given, ToInteger(undefined) = 0, which is correct + * for indexOf() but incorrect for lastIndexOf(). Hence special handling, + * and why lastIndexOf() needs to be a vararg function. + */ + + if (nargs >= 2) { + /* indexOf: clamp fromIndex to [-len, len] + * (if fromIndex == len, for-loop terminates directly) + * + * lastIndexOf: clamp fromIndex to [-len - 1, len - 1] + * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly) + */ + from_index = duk_to_int_clamped(ctx, + 1, + (idx_step > 0 ? -len : -len - 1), + (idx_step > 0 ? len : len - 1)); + if (from_index < 0) { + /* for lastIndexOf, result may be -1 (mark immediate termination) */ + from_index = len + from_index; + } + } else { + /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but + * handle both indexOf and lastIndexOf specially here. + */ + if (idx_step > 0) { + from_index = 0; + } else { + from_index = len - 1; + } + } + + /* stack[0] = searchElement + * stack[1] = fromIndex + * stack[2] = object + * stack[3] = length (not needed, but not popped above) + */ + + for (i = from_index; i >= 0 && i < len; i += idx_step) { + DUK_ASSERT_TOP(ctx, 4); + + if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) { + DUK_ASSERT_TOP(ctx, 5); + if (duk_strict_equals(ctx, 0, 4)) { + duk_push_int(ctx, i); + return 1; + } + } + + duk_pop(ctx); + } + + not_found: + duk_push_int(ctx, -1); + return 1; +} + +/* + * every(), some(), forEach(), map(), filter() + */ + +#define DUK__ITER_EVERY 0 +#define DUK__ITER_SOME 1 +#define DUK__ITER_FOREACH 2 +#define DUK__ITER_MAP 3 +#define DUK__ITER_FILTER 4 + +/* XXX: This helper is a bit awkward because the handling for the different iteration + * callers is quite different. This now compiles to a bit less than 500 bytes, so with + * 5 callers the net result is about 100 bytes / caller. + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) { + duk_uint32_t len; + duk_uint32_t i; + duk_uarridx_t k; + duk_bool_t bval; + duk_small_int_t iter_type = duk_get_current_magic(ctx); + duk_uint32_t res_length = 0; + + /* each call this helper serves has nargs==2 */ + DUK_ASSERT_TOP(ctx, 2); + + len = duk__push_this_obj_len_u32(ctx); + duk_require_callable(ctx, 0); + /* if thisArg not supplied, behave as if undefined was supplied */ + + if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) { + duk_push_array(ctx); + } else { + duk_push_undefined(ctx); + } + + /* stack[0] = callback + * stack[1] = thisArg + * stack[2] = object + * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop) + * stack[4] = result array (or undefined) + */ + + k = 0; /* result index for filter() */ + for (i = 0; i < len; i++) { + DUK_ASSERT_TOP(ctx, 5); + + if (!duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) { +#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER) + /* Real world behavior for map(): trailing non-existent + * elements don't invoke the user callback, but are still + * counted towards result 'length'. + */ + if (iter_type == DUK__ITER_MAP) { + res_length = i + 1; + } +#else + /* Standard behavior for map(): trailing non-existent + * elements don't invoke the user callback and are not + * counted towards result 'length'. + */ +#endif + duk_pop(ctx); + continue; + } + + /* The original value needs to be preserved for filter(), hence + * this funny order. We can't re-get the value because of side + * effects. + */ + + duk_dup(ctx, 0); + duk_dup(ctx, 1); + duk_dup(ctx, -3); + duk_push_u32(ctx, i); + duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */ + duk_call_method(ctx, 3); /* -> [ ... val retval ] */ + + switch (iter_type) { + case DUK__ITER_EVERY: + bval = duk_to_boolean(ctx, -1); + if (!bval) { + /* stack top contains 'false' */ + return 1; + } + break; + case DUK__ITER_SOME: + bval = duk_to_boolean(ctx, -1); + if (bval) { + /* stack top contains 'true' */ + return 1; + } + break; + case DUK__ITER_FOREACH: + /* nop */ + break; + case DUK__ITER_MAP: + duk_dup(ctx, -1); + duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */ + res_length = i + 1; + break; + case DUK__ITER_FILTER: + bval = duk_to_boolean(ctx, -1); + if (bval) { + duk_dup(ctx, -2); /* orig value */ + duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k); + k++; + res_length = k; + } + break; + default: + DUK_UNREACHABLE(); + break; + } + duk_pop_2(ctx); + + DUK_ASSERT_TOP(ctx, 5); + } + + switch (iter_type) { + case DUK__ITER_EVERY: + duk_push_true(ctx); + break; + case DUK__ITER_SOME: + duk_push_false(ctx); + break; + case DUK__ITER_FOREACH: + duk_push_undefined(ctx); + break; + case DUK__ITER_MAP: + case DUK__ITER_FILTER: + DUK_ASSERT_TOP(ctx, 5); + DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */ + duk_push_u32(ctx, res_length); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); + break; + default: + DUK_UNREACHABLE(); + break; + } + + return 1; +} + +/* + * reduce(), reduceRight() + */ + +DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) { + duk_idx_t nargs; + duk_bool_t have_acc; + duk_uint32_t i, len; + duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */ + + /* We're a varargs function because we need to detect whether + * initialValue was given or not. + */ + nargs = duk_get_top(ctx); + DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs)); + + duk_set_top(ctx, 2); + len = duk__push_this_obj_len_u32(ctx); + if (!duk_is_callable(ctx, 0)) { + goto type_error; + } + + /* stack[0] = callback fn + * stack[1] = initialValue + * stack[2] = object (coerced this) + * stack[3] = length (not needed, but not popped above) + * stack[4] = accumulator + */ + + have_acc = 0; + if (nargs >= 2) { + duk_dup(ctx, 1); + have_acc = 1; + } + DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T", + (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3))); + + /* For len == 0, i is initialized to len - 1 which underflows. + * The condition (i < len) will then exit the for-loop on the + * first round which is correct. Similarly, loop termination + * happens by i underflowing. + */ + + for (i = (idx_step >= 0 ? 0 : len - 1); + i < len; /* i >= 0 would always be true */ + i += idx_step) { + DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T", + (long) i, (long) len, (long) have_acc, + (long) duk_get_top(ctx), + (duk_tval *) duk_get_tval(ctx, 4))); + + DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) || + (!have_acc && duk_get_top(ctx) == 4)); + + if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) { + continue; + } + + if (!have_acc) { + DUK_ASSERT_TOP(ctx, 4); + duk_get_prop_index(ctx, 2, (duk_uarridx_t) i); + have_acc = 1; + DUK_ASSERT_TOP(ctx, 5); + } else { + DUK_ASSERT_TOP(ctx, 5); + duk_dup(ctx, 0); + duk_dup(ctx, 4); + duk_get_prop_index(ctx, 2, (duk_uarridx_t) i); + duk_push_u32(ctx, i); + duk_dup(ctx, 2); + DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T", + (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4), + (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2), + (duk_tval *) duk_get_tval(ctx, -1))); + duk_call(ctx, 4); + DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1))); + duk_replace(ctx, 4); + DUK_ASSERT_TOP(ctx, 5); + } + } + + if (!have_acc) { + goto type_error; + } + + DUK_ASSERT_TOP(ctx, 5); + return 1; + + type_error: + return DUK_RET_TYPE_ERROR; +} + +#undef DUK__ARRAY_MID_JOIN_LIMIT + +#undef DUK__ITER_EVERY +#undef DUK__ITER_SOME +#undef DUK__ITER_FOREACH +#undef DUK__ITER_MAP +#undef DUK__ITER_FILTER +/* + * Boolean built-ins + */ + +/* include removed: duk_internal.h */ + +/* Shared helper to provide toString() and valueOf(). Checks 'this', gets + * the primitive value to stack top, and optionally coerces with ToString(). + */ +DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) { + duk_tval *tv; + duk_hobject *h; + duk_small_int_t coerce_tostring = duk_get_current_magic(ctx); + + /* XXX: there is room to use a shared helper here, many built-ins + * check the 'this' type, and if it's an object, check its class, + * then get its internal value, etc. + */ + + duk_push_this(ctx); + tv = duk_get_tval(ctx, -1); + DUK_ASSERT(tv != NULL); + + if (DUK_TVAL_IS_BOOLEAN(tv)) { + goto type_ok; + } else if (DUK_TVAL_IS_OBJECT(tv)) { + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + + if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) { + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); + DUK_ASSERT(duk_is_boolean(ctx, -1)); + goto type_ok; + } + } + + return DUK_RET_TYPE_ERROR; + + type_ok: + if (coerce_tostring) { + duk_to_string(ctx, -1); + } + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *h_this; + + DUK_UNREF(thr); + + duk_to_boolean(ctx, 0); + + if (duk_is_constructor_call(ctx)) { + /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */ + duk_push_this(ctx); + h_this = duk_get_hobject(ctx, -1); + DUK_ASSERT(h_this != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]); + + DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN); + + duk_dup(ctx, 0); /* -> [ val obj val ] */ + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */ + } /* unbalanced stack */ + + return 1; +} +/* + * Duktape.Buffer, Node.js Buffer, and Khronos/ES6 TypedArray built-ins + */ + +/* include removed: duk_internal.h */ + +/* + * Misc helpers + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Map DUK_HBUFFEROBJECT_ELEM_xxx to duk_hobject class number. + * Sync with duk_hbufferobject.h and duk_hobject.h. + */ +static const duk_uint8_t duk__buffer_class_from_elemtype[9] = { + DUK_HOBJECT_CLASS_UINT8ARRAY, + DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, + DUK_HOBJECT_CLASS_INT8ARRAY, + DUK_HOBJECT_CLASS_UINT16ARRAY, + DUK_HOBJECT_CLASS_INT16ARRAY, + DUK_HOBJECT_CLASS_UINT32ARRAY, + DUK_HOBJECT_CLASS_INT32ARRAY, + DUK_HOBJECT_CLASS_FLOAT32ARRAY, + DUK_HOBJECT_CLASS_FLOAT64ARRAY +}; +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Map DUK_HBUFFEROBJECT_ELEM_xxx to prototype object built-in index. + * Sync with duk_hbufferobject.h. + */ +static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = { + DUK_BIDX_UINT8ARRAY_PROTOTYPE, + DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, + DUK_BIDX_INT8ARRAY_PROTOTYPE, + DUK_BIDX_UINT16ARRAY_PROTOTYPE, + DUK_BIDX_INT16ARRAY_PROTOTYPE, + DUK_BIDX_UINT32ARRAY_PROTOTYPE, + DUK_BIDX_INT32ARRAY_PROTOTYPE, + DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, + DUK_BIDX_FLOAT64ARRAY_PROTOTYPE +}; +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Map DUK__FLX_xxx to byte size. + */ +static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = { + 1, /* DUK__FLD_8BIT */ + 2, /* DUK__FLD_16BIT */ + 4, /* DUK__FLD_32BIT */ + 4, /* DUK__FLD_FLOAT */ + 8, /* DUK__FLD_DOUBLE */ + 0 /* DUK__FLD_VARINT; not relevant here */ +}; +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Bitfield for each DUK_HBUFFEROBJECT_ELEM_xxx indicating which element types + * are compatible with a blind byte copy for the TypedArray set() method (also + * used for TypedArray constructor). Array index is target buffer elem type, + * bitfield indicates compatible source types. The types must have same byte + * size and they must be coercion compatible. + */ +static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = { + /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8 */ + (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) | + (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) | + (1U << DUK_HBUFFEROBJECT_ELEM_INT8), + + /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED + * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00. + */ + (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) | + (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED), + + /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT8 */ + (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) | + (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) | + (1U << DUK_HBUFFEROBJECT_ELEM_INT8), + + /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT16 */ + (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) | + (1U << DUK_HBUFFEROBJECT_ELEM_INT16), + + /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT16 */ + (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) | + (1U << DUK_HBUFFEROBJECT_ELEM_INT16), + + /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT32 */ + (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) | + (1U << DUK_HBUFFEROBJECT_ELEM_INT32), + + /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT32 */ + (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) | + (1U << DUK_HBUFFEROBJECT_ELEM_INT32), + + /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT32 */ + (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT32), + + /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT64 */ + (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT64) +}; +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Shared helper. */ +DUK_LOCAL duk_hbufferobject *duk__getrequire_bufobj_this(duk_context *ctx, duk_bool_t throw_flag) { + duk_hthread *thr; + duk_tval *tv; + duk_hbufferobject *h_this; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + + tv = duk_get_borrowed_this_tval(ctx); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_OBJECT(tv)) { + h_this = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h_this != NULL); + if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_this)) { + DUK_ASSERT_HBUFFEROBJECT_VALID(h_this); + return h_this; + } + } + + if (throw_flag) { + DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); + } + return NULL; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Check that 'this' is a duk_hbufferobject and return a pointer to it. */ +DUK_LOCAL duk_hbufferobject *duk__get_bufobj_this(duk_context *ctx) { + return duk__getrequire_bufobj_this(ctx, 0); +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Check that 'this' is a duk_hbufferobject and return a pointer to it + * (NULL if not). + */ +DUK_LOCAL duk_hbufferobject *duk__require_bufobj_this(duk_context *ctx) { + return duk__getrequire_bufobj_this(ctx, 1); +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Check that value is a duk_hbufferobject and return a pointer to it. */ +DUK_LOCAL duk_hbufferobject *duk__require_bufobj_value(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr; + duk_tval *tv; + duk_hbufferobject *h_obj; + + thr = (duk_hthread *) ctx; + + /* Don't accept relative indices now. */ + DUK_ASSERT(index >= 0); + + tv = duk_require_tval(ctx, index); + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_OBJECT(tv)) { + h_obj = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h_obj != NULL); + if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_obj)) { + DUK_ASSERT_HBUFFEROBJECT_VALID(h_obj); + return h_obj; + } + } + + DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); + return NULL; /* not reachable */ +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_hbuffer *h_val) { + duk_hthread *thr; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + DUK_ASSERT(ctx != NULL); + DUK_ASSERT(h_bufobj != NULL); + DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */ + DUK_ASSERT(h_val != NULL); + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + h_bufobj->buf = h_val; + DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val); + DUK_ASSERT(h_bufobj->shift == 0); + DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8); + + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); +} + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_LOCAL duk_hbufferobject *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) { + duk_hbuffer *h_val; + duk_hbufferobject *h_bufobj; + + (void) duk_push_fixed_buffer(ctx, (duk_size_t) len); + h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1); + DUK_ASSERT(h_val != NULL); + + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + DUK_ASSERT(h_bufobj != NULL); + + duk__set_bufobj_buffer(ctx, h_bufobj, h_val); + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + return h_bufobj; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Shared offset/length coercion helper. */ +DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx, + duk_hbufferobject *h_bufarg, + duk_idx_t idx_offset, + duk_idx_t idx_length, + duk_uint_t *out_offset, + duk_uint_t *out_length, + duk_bool_t throw_flag) { + duk_hthread *thr; + duk_int_t offset_signed; + duk_int_t length_signed; + duk_uint_t offset; + duk_uint_t length; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + offset_signed = duk_to_int(ctx, idx_offset); + if (offset_signed < 0) { + goto fail_range; + } + offset = (duk_uint_t) offset_signed; + if (offset > h_bufarg->length) { + goto fail_range; + } + DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */ + DUK_ASSERT(offset <= h_bufarg->length); + + if (duk_is_undefined(ctx, idx_length)) { + DUK_ASSERT(h_bufarg->length >= offset); + length = h_bufarg->length - offset; /* >= 0 */ + } else { + length_signed = duk_to_int(ctx, idx_length); + if (length_signed < 0) { + goto fail_range; + } + length = (duk_uint_t) length_signed; + DUK_ASSERT(h_bufarg->length >= offset); + if (length > h_bufarg->length - offset) { + /* Unlike for negative arguments, some call sites + * want length to be clamped if it's positive. + */ + if (throw_flag) { + goto fail_range; + } else { + length = h_bufarg->length - offset; + } + } + } + DUK_ASSERT_DISABLE(length >= 0); /* unsigned */ + DUK_ASSERT(offset + length <= h_bufarg->length); + + *out_offset = offset; + *out_length = length; + return; + + fail_range: + DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS); +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Shared lenient buffer length clamping helper. No negative indices, no + * element/byte shifting. + */ +DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx, + duk_hbufferobject *h_bufobj, + duk_idx_t idx_start, + duk_idx_t idx_end, + duk_int_t *out_start_offset, + duk_int_t *out_end_offset) { + duk_int_t buffer_length; + duk_int_t start_offset; + duk_int_t end_offset; + + DUK_ASSERT(out_start_offset != NULL); + DUK_ASSERT(out_end_offset != NULL); + + buffer_length = (duk_int_t) h_bufobj->length; + + /* undefined coerces to zero which is correct */ + start_offset = duk_to_int_clamped(ctx, idx_start, 0, buffer_length); + if (duk_is_undefined(ctx, idx_end)) { + end_offset = buffer_length; + } else { + end_offset = duk_to_int_clamped(ctx, idx_end, start_offset, buffer_length); + } + + DUK_ASSERT(start_offset >= 0); + DUK_ASSERT(start_offset <= buffer_length); + DUK_ASSERT(end_offset >= 0); + DUK_ASSERT(end_offset <= buffer_length); + DUK_ASSERT(start_offset <= end_offset); + + *out_start_offset = start_offset; + *out_end_offset = end_offset; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Shared lenient buffer length clamping helper. Indices are treated as + * element indices (though output values are byte offsets) which only + * really matters for TypedArray views as other buffer object have a zero + * shift. Negative indices are counted from end of input slice; crossed + * indices are clamped to zero length; and final indices are clamped + * against input slice. Used for e.g. ArrayBuffer slice(). + */ +DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx, + duk_hbufferobject *h_bufobj, + duk_idx_t idx_start, + duk_idx_t idx_end, + duk_int_t *out_start_offset, + duk_int_t *out_end_offset) { + duk_int_t buffer_length; + duk_int_t start_offset; + duk_int_t end_offset; + + DUK_ASSERT(out_start_offset != NULL); + DUK_ASSERT(out_end_offset != NULL); + + buffer_length = (duk_int_t) h_bufobj->length; + buffer_length >>= h_bufobj->shift; /* as elements */ + + /* Resolve start/end offset as element indices first; arguments + * at idx_start/idx_end are element offsets. Working with element + * indices first also avoids potential for wrapping. + */ + + start_offset = duk_to_int(ctx, idx_start); + if (start_offset < 0) { + start_offset = buffer_length + start_offset; + } + if (duk_is_undefined(ctx, idx_end)) { + end_offset = buffer_length; + } else { + end_offset = duk_to_int(ctx, idx_end); + if (end_offset < 0) { + end_offset = buffer_length + end_offset; + } + } + /* Note: start_offset/end_offset can still be < 0 here. */ + + if (start_offset < 0) { + start_offset = 0; + } else if (start_offset > buffer_length) { + start_offset = buffer_length; + } + if (end_offset < start_offset) { + end_offset = start_offset; + } else if (end_offset > buffer_length) { + end_offset = buffer_length; + } + DUK_ASSERT(start_offset >= 0); + DUK_ASSERT(start_offset <= buffer_length); + DUK_ASSERT(end_offset >= 0); + DUK_ASSERT(end_offset <= buffer_length); + DUK_ASSERT(start_offset <= end_offset); + + /* Convert indices to byte offsets. */ + start_offset <<= h_bufobj->shift; + end_offset <<= h_bufobj->shift; + + *out_start_offset = start_offset; + *out_end_offset = end_offset; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Indexed read/write helpers (also used from outside this file) + */ + +DUK_INTERNAL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { + duk_double_union du; + + DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size); + + switch (h_bufobj->elem_type) { + case DUK_HBUFFEROBJECT_ELEM_UINT8: +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) + case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED: +#endif + duk_push_uint(ctx, (duk_uint_t) du.uc[0]); + break; +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) + /* These are not needed when only Duktape.Buffer is supported. */ + case DUK_HBUFFEROBJECT_ELEM_INT8: + duk_push_int(ctx, (duk_int_t) (duk_int8_t) du.uc[0]); + break; + case DUK_HBUFFEROBJECT_ELEM_UINT16: + duk_push_uint(ctx, (duk_uint_t) du.us[0]); + break; + case DUK_HBUFFEROBJECT_ELEM_INT16: + duk_push_int(ctx, (duk_int_t) (duk_int16_t) du.us[0]); + break; + case DUK_HBUFFEROBJECT_ELEM_UINT32: + duk_push_uint(ctx, (duk_uint_t) du.ui[0]); + break; + case DUK_HBUFFEROBJECT_ELEM_INT32: + duk_push_int(ctx, (duk_int_t) (duk_int32_t) du.ui[0]); + break; + case DUK_HBUFFEROBJECT_ELEM_FLOAT32: + duk_push_number(ctx, (duk_double_t) du.f[0]); + break; + case DUK_HBUFFEROBJECT_ELEM_FLOAT64: + duk_push_number(ctx, (duk_double_t) du.d); + break; +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + default: + DUK_UNREACHABLE(); + } +} + +DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { + duk_double_union du; + + /* NOTE! Caller must ensure that any side effects from the + * coercions below are safe. If that cannot be guaranteed + * (which is normally the case), caller must coerce the + * argument using duk_to_number() before any pointer + * validations; the result of duk_to_number() always coerces + * without side effects here. + */ + + switch (h_bufobj->elem_type) { + case DUK_HBUFFEROBJECT_ELEM_UINT8: + du.uc[0] = (duk_uint8_t) duk_to_uint32(ctx, -1); + break; +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) + /* These are not needed when only Duktape.Buffer is supported. */ + case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED: + du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(ctx, -1); + break; + case DUK_HBUFFEROBJECT_ELEM_INT8: + du.uc[0] = (duk_uint8_t) duk_to_int32(ctx, -1); + break; + case DUK_HBUFFEROBJECT_ELEM_UINT16: + du.us[0] = (duk_uint16_t) duk_to_uint32(ctx, -1); + break; + case DUK_HBUFFEROBJECT_ELEM_INT16: + du.us[0] = (duk_uint16_t) duk_to_int32(ctx, -1); + break; + case DUK_HBUFFEROBJECT_ELEM_UINT32: + du.ui[0] = (duk_uint32_t) duk_to_uint32(ctx, -1); + break; + case DUK_HBUFFEROBJECT_ELEM_INT32: + du.ui[0] = (duk_uint32_t) duk_to_int32(ctx, -1); + break; + case DUK_HBUFFEROBJECT_ELEM_FLOAT32: + du.f[0] = (duk_float_t) duk_to_number(ctx, -1); + break; + case DUK_HBUFFEROBJECT_ELEM_FLOAT64: + du.d = (duk_double_t) duk_to_number(ctx, -1); + break; +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + default: + DUK_UNREACHABLE(); + } + + DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size); +} + +/* + * Duktape.Buffer: constructor + */ + +DUK_INTERNAL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx) { + duk_hthread *thr; + duk_size_t buf_size; + duk_small_int_t buf_dynamic; + duk_uint8_t *buf_data; + const duk_uint8_t *src_data; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + /* + * Constructor arguments are currently somewhat compatible with + * (keep it that way if possible): + * + * http://nodejs.org/api/buffer.html + * + * Note that the ToBuffer() coercion (duk_to_buffer()) does NOT match + * the constructor behavior. + */ + + buf_dynamic = duk_get_boolean(ctx, 1); /* default to false */ + + switch (duk_get_type(ctx, 0)) { + case DUK_TYPE_NUMBER: { + /* new buffer of specified size */ + buf_size = (duk_size_t) duk_to_int(ctx, 0); + (void) duk_push_buffer(ctx, buf_size, buf_dynamic); + break; + } + case DUK_TYPE_BUFFER: { + /* return input buffer, converted to a Duktape.Buffer object + * if called as a constructor (no change if called as a + * function). + */ + duk_set_top(ctx, 1); + break; + } + case DUK_TYPE_STRING: { + /* new buffer with string contents */ + src_data = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &buf_size); + DUK_ASSERT(src_data != NULL); /* even for zero-length string */ + buf_data = (duk_uint8_t *) duk_push_buffer(ctx, buf_size, buf_dynamic); + DUK_MEMCPY((void *) buf_data, (const void *) src_data, (size_t) buf_size); + break; + } + case DUK_TYPE_OBJECT: { + /* For all duk_hbufferobjects, get the plain buffer inside + * without making a copy. This is compatible with Duktape 1.2 + * but means that a slice/view information is ignored and the + * full underlying buffer is returned. + * + * If called as a constructor, a new Duktape.Buffer object + * pointing to the same plain buffer is created below. + */ + duk_hbufferobject *h_bufobj; + h_bufobj = (duk_hbufferobject *) duk_get_hobject(ctx, 0); + DUK_ASSERT(h_bufobj != NULL); + if (!DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj)) { + return DUK_RET_TYPE_ERROR; + } + if (h_bufobj->buf == NULL) { + return DUK_RET_TYPE_ERROR; + } + duk_push_hbuffer(ctx, h_bufobj->buf); + break; + } + case DUK_TYPE_NONE: + default: { + return DUK_RET_TYPE_ERROR; + } + } + DUK_ASSERT(duk_is_buffer(ctx, -1)); + + /* stack is unbalanced, but: [ buf ] */ + + if (duk_is_constructor_call(ctx)) { + duk_hbufferobject *h_bufobj; + duk_hbuffer *h_val; + + h_val = duk_get_hbuffer(ctx, -1); + DUK_ASSERT(h_val != NULL); + + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER), + DUK_BIDX_BUFFER_PROTOTYPE); + DUK_ASSERT(h_bufobj != NULL); + + duk__set_bufobj_buffer(ctx, h_bufobj, h_val); + + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + } + /* Note: unbalanced stack on purpose */ + + return 1; +} + +/* + * Node.js Buffer: constructor + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) { + /* Internal class is Object: Object.prototype.toString.call(new Buffer(0)) + * prints "[object Object]". + */ + duk_int_t len; + duk_int_t i; + duk_hbuffer *h_buf; + duk_hbufferobject *h_bufobj; + duk_size_t buf_size; + + switch (duk_get_type(ctx, 0)) { + case DUK_TYPE_BUFFER: { + /* Custom behavior: plain buffer is used as internal buffer + * without making a copy (matches Duktape.Buffer). + */ + duk_set_top(ctx, 1); /* -> [ buffer ] */ + break; + } + case DUK_TYPE_NUMBER: { + len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX); + (void) duk_push_fixed_buffer(ctx, (duk_size_t) len); + break; + } + case DUK_TYPE_OBJECT: { + duk_uint8_t *buf; + + (void) duk_get_prop_string(ctx, 0, "length"); + len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX); + duk_pop(ctx); + buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len); + for (i = 0; i < len; i++) { + /* XXX: fast path for array arguments? */ + duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); + buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU); + duk_pop(ctx); + } + break; + } + case DUK_TYPE_STRING: { + /* ignore encoding for now */ + duk_dup(ctx, 0); + (void) duk_to_buffer(ctx, -1, &buf_size); + break; + } + default: + return DUK_RET_TYPE_ERROR; + } + + DUK_ASSERT(duk_is_buffer(ctx, -1)); + h_buf = duk_get_hbuffer(ctx, -1); + DUK_ASSERT(h_buf != NULL); + + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER), + DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); + DUK_ASSERT(h_bufobj != NULL); + + h_bufobj->buf = h_buf; + DUK_HBUFFER_INCREF(thr, h_buf); + DUK_ASSERT(h_bufobj->offset == 0); + h_bufobj->length = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_buf); + DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8); + + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * ArrayBuffer, DataView, and TypedArray constructors + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) { + duk_hthread *thr; + duk_hbufferobject *h_bufobj; + duk_hbuffer *h_val; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + /* XXX: function flag to make this automatic? */ + if (!duk_is_constructor_call(ctx)) { + return DUK_RET_TYPE_ERROR; + } + + if (duk_is_buffer(ctx, 0)) { + /* Custom behavior: plain buffer is used as internal buffer + * without making a copy (matches Duktape.Buffer). + */ + + h_val = duk_get_hbuffer(ctx, 0); + DUK_ASSERT(h_val != NULL); + + /* XXX: accept any duk_hbufferobject type as an input also? */ + } else { + duk_int_t len; + len = duk_to_int(ctx, 0); + if (len < 0) { + goto fail_length; + } + (void) duk_push_fixed_buffer(ctx, (duk_size_t) len); + h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1); + DUK_ASSERT(h_val != NULL); + +#if !defined(DUK_USE_ZERO_BUFFER_DATA) + /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA + * is not set. + */ + DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val)); + DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) len); +#endif + } + + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + DUK_ASSERT(h_bufobj != NULL); + + duk__set_bufobj_buffer(ctx, h_bufobj, h_val); + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + return 1; + + fail_length: + return DUK_RET_RANGE_ERROR; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + + +/* Format of magic, bits: + * 0...1: elem size shift (0-3) + * 2...5: elem type (DUK_HBUFFEROBJECT_ELEM_xxx) + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv; + duk_hobject *h_obj; + duk_hbufferobject *h_bufobj = NULL; + duk_hbufferobject *h_bufarr = NULL; + duk_hbufferobject *h_bufarg = NULL; + duk_hbuffer *h_val; + duk_small_uint_t magic; + duk_small_uint_t shift; + duk_small_uint_t elem_type; + duk_small_uint_t elem_size; + duk_small_uint_t class_num; + duk_small_uint_t proto_bidx; + duk_uint_t align_mask; + duk_uint_t elem_length; + duk_int_t elem_length_signed; + duk_uint_t byte_length; + duk_small_uint_t copy_mode; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + /* XXX: function flag to make this automatic? */ + if (!duk_is_constructor_call(ctx)) { + return DUK_RET_TYPE_ERROR; + } + + /* We could fit built-in index into magic but that'd make the magic + * number dependent on built-in numbering (genbuiltins.py doesn't + * handle that yet). So map both class and prototype from the + * element type. + */ + magic = duk_get_current_magic(ctx); + shift = magic & 0x03; /* bits 0...1: shift */ + elem_type = (magic >> 2) & 0x0f; /* bits 2...5: type */ + elem_size = 1 << shift; + align_mask = elem_size - 1; + DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t)); + proto_bidx = duk__buffer_proto_from_elemtype[elem_type]; + DUK_ASSERT(proto_bidx < DUK_NUM_BUILTINS); + DUK_ASSERT(elem_type < sizeof(duk__buffer_class_from_elemtype) / sizeof(duk_uint8_t)); + class_num = duk__buffer_class_from_elemtype[elem_type]; + + DUK_DD(DUK_DDPRINT("typedarray constructor, magic=%d, shift=%d, elem_type=%d, " + "elem_size=%d, proto_bidx=%d, class_num=%d", + (int) magic, (int) shift, (int) elem_type, (int) elem_size, + (int) proto_bidx, (int) class_num)); + + /* Argument variants. When the argument is an ArrayBuffer a view to + * the same buffer is created; otherwise a new ArrayBuffer is always + * created. + */ + + tv = duk_get_tval(ctx, 0); + DUK_ASSERT(tv != NULL); /* arg count */ + if (DUK_TVAL_IS_OBJECT(tv)) { + h_obj = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h_obj != NULL); + + if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_ARRAYBUFFER) { + /* ArrayBuffer: unlike any other argument variant, create + * a view into the existing buffer. + */ + + duk_int_t byte_offset_signed; + duk_uint_t byte_offset; + + h_bufarg = (duk_hbufferobject *) h_obj; + + byte_offset_signed = duk_to_int(ctx, 1); + if (byte_offset_signed < 0) { + goto fail_arguments; + } + byte_offset = (duk_uint_t) byte_offset_signed; + if (byte_offset > h_bufarg->length || + (byte_offset & align_mask) != 0) { + /* Must be >= 0 and multiple of element size. */ + goto fail_arguments; + } + if (duk_is_undefined(ctx, 2)) { + DUK_ASSERT(h_bufarg->length >= byte_offset); + byte_length = h_bufarg->length - byte_offset; + if ((byte_length & align_mask) != 0) { + /* Must be element size multiple from + * start offset to end of buffer. + */ + goto fail_arguments; + } + elem_length = (byte_length >> shift); + } else { + elem_length_signed = duk_to_int(ctx, 2); + if (elem_length_signed < 0) { + goto fail_arguments; + } + elem_length = (duk_uint_t) elem_length_signed; + byte_length = elem_length << shift; + if ((byte_length >> shift) != elem_length) { + /* Byte length would overflow. */ + /* XXX: easier check with less code? */ + goto fail_arguments; + } + DUK_ASSERT(h_bufarg->length >= byte_offset); + if (byte_length > h_bufarg->length - byte_offset) { + /* Not enough data. */ + goto fail_arguments; + } + } + DUK_UNREF(elem_length); + DUK_ASSERT_DISABLE(byte_offset >= 0); + DUK_ASSERT(byte_offset <= h_bufarg->length); + DUK_ASSERT_DISABLE(byte_length >= 0); + DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length); + DUK_ASSERT((elem_length << shift) == byte_length); + + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(class_num), + proto_bidx); + h_val = h_bufarg->buf; + if (h_val == NULL) { + return DUK_RET_TYPE_ERROR; + } + h_bufobj->buf = h_val; + DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->offset = h_bufarg->offset + byte_offset; + h_bufobj->length = byte_length; + h_bufobj->shift = (duk_uint8_t) shift; + h_bufobj->elem_type = (duk_uint8_t) elem_type; + h_bufobj->is_view = 1; + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + /* Set .buffer to the argument ArrayBuffer. */ + duk_dup(ctx, 0); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); + duk_compact(ctx, -1); + return 1; + } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) { + /* TypedArray (or other non-ArrayBuffer duk_hbufferobject). + * Conceptually same behavior as for an Array-like argument, + * with a few fast paths. + */ + + h_bufarg = (duk_hbufferobject *) h_obj; + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg); + elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift); + if (h_bufarg->buf == NULL) { + return DUK_RET_TYPE_ERROR; + } + + /* Select copy mode. Must take into account element + * compatibility and validity of the underlying source + * buffer. + */ + + DUK_DDD(DUK_DDDPRINT("selecting copy mode for bufobj arg, " + "src byte_length=%ld, src shift=%d, " + "src/dst elem_length=%ld; " + "dst shift=%d -> dst byte_length=%ld", + (long) h_bufarg->length, (int) h_bufarg->shift, + (long) elem_length_signed, (int) shift, + (long) (elem_length_signed << shift))); + + copy_mode = 2; /* default is explicit index read/write copy */ + DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t)); + if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) { + if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) { + DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy")); + DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */ + copy_mode = 0; + } else { + DUK_DDD(DUK_DDDPRINT("source/target not copy compatible but valid, fast copy")); + copy_mode = 1; + } + } + } else { + /* Array or Array-like */ + elem_length_signed = (duk_int_t) duk_get_length(ctx, 0); + copy_mode = 2; + } + } else if (DUK_TVAL_IS_BUFFER(tv)) { + /* Accept plain buffer values like array initializers + * (new in Duktape 1.4.0). + */ + duk_hbuffer *h_srcbuf; + h_srcbuf = DUK_TVAL_GET_BUFFER(tv); + elem_length_signed = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_srcbuf); + copy_mode = 2; /* XXX: could add fast path for u8 compatible views */ + } else { + /* Non-object argument is simply int coerced, matches + * V8 behavior (except for "null", which we coerce to + * 0 but V8 TypeErrors). + */ + elem_length_signed = duk_to_int(ctx, 0); + copy_mode = 3; + } + if (elem_length_signed < 0) { + goto fail_arguments; + } + elem_length = (duk_uint_t) elem_length_signed; + byte_length = (duk_uint_t) (elem_length << shift); + if ((byte_length >> shift) != elem_length) { + /* Byte length would overflow. */ + /* XXX: easier check with less code? */ + goto fail_arguments; + } + + DUK_DDD(DUK_DDDPRINT("elem_length=%ld, byte_length=%ld", + (long) elem_length, (long) byte_length)); + + /* ArrayBuffer argument is handled specially above; the rest of the + * argument variants are handled by shared code below. + */ + + /* Push a new ArrayBuffer (becomes view .buffer) */ + h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length); + DUK_ASSERT(h_bufarr != NULL); + h_val = h_bufarr->buf; + DUK_ASSERT(h_val != NULL); + + /* Push the resulting view object and attach the ArrayBuffer. */ + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(class_num), + proto_bidx); + + h_bufobj->buf = h_val; + DUK_HBUFFER_INCREF(thr, h_val); + DUK_ASSERT(h_bufobj->offset == 0); + h_bufobj->length = byte_length; + h_bufobj->shift = (duk_uint8_t) shift; + h_bufobj->elem_type = (duk_uint8_t) elem_type; + h_bufobj->is_view = 1; + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + /* Set .buffer */ + duk_dup(ctx, -2); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); + duk_compact(ctx, -1); + + /* Copy values, the copy method depends on the arguments. + * + * Copy mode decision may depend on the validity of the underlying + * buffer of the source argument; there must be no harmful side effects + * from there to here for copy_mode to still be valid. + */ + DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode)); + switch (copy_mode) { + case 0: { + /* Use byte copy. */ + + duk_uint8_t *p_src; + duk_uint8_t *p_dst; + + DUK_ASSERT(h_bufobj != NULL); + DUK_ASSERT(h_bufobj->buf != NULL); + DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)); + DUK_ASSERT(h_bufarg != NULL); + DUK_ASSERT(h_bufarg->buf != NULL); + DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)); + + p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj); + p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg); + + DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld", + (void *) p_src, (void *) p_dst, (long) byte_length)); + + DUK_MEMCPY((void *) p_dst, (const void *) p_src, (size_t) byte_length); + break; + } + case 1: { + /* Copy values through direct validated reads and writes. */ + + duk_small_uint_t src_elem_size; + duk_small_uint_t dst_elem_size; + duk_uint8_t *p_src; + duk_uint8_t *p_src_end; + duk_uint8_t *p_dst; + + DUK_ASSERT(h_bufobj != NULL); + DUK_ASSERT(h_bufobj->buf != NULL); + DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)); + DUK_ASSERT(h_bufarg != NULL); + DUK_ASSERT(h_bufarg->buf != NULL); + DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)); + + src_elem_size = 1 << h_bufarg->shift; + dst_elem_size = elem_size; + + p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg); + p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj); + p_src_end = p_src + h_bufarg->length; + + DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, " + "src_elem_size=%d, dst_elem_size=%d", + (void *) p_src, (void *) p_src_end, (void *) p_dst, + (int) src_elem_size, (int) dst_elem_size)); + + while (p_src != p_src_end) { + DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: " + "p_src=%p, p_src_end=%p, p_dst=%p", + (void *) p_src, (void *) p_src_end, (void *) p_dst)); + /* A validated read() is always a number, so it's write coercion + * is always side effect free an won't invalidate pointers etc. + */ + duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size); + duk_hbufferobject_validated_write(ctx, h_bufobj, p_dst, dst_elem_size); + duk_pop(ctx); + p_src += src_elem_size; + p_dst += dst_elem_size; + } + break; + } + case 2: { + /* Copy values by index reads and writes. Let virtual + * property handling take care of coercion. + */ + duk_uint_t i; + + DUK_DDD(DUK_DDDPRINT("using slow copy")); + + for (i = 0; i < elem_length; i++) { + duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); + duk_put_prop_index(ctx, -2, (duk_uarridx_t) i); + } + break; + } + default: + case 3: { + /* No copy, leave zero bytes in the buffer. There's no + * ambiguity with Float32/Float64 because zero bytes also + * represent 0.0. + */ +#if !defined(DUK_USE_ZERO_BUFFER_DATA) + /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA + * is not set. + */ + DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val)); + DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) byte_length); +#endif + + DUK_DDD(DUK_DDDPRINT("using no copy")); + break; + } + } + + return 1; + + fail_arguments: + return DUK_RET_RANGE_ERROR; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) { + duk_hbufferobject *h_bufarg; + duk_hbufferobject *h_bufobj; + duk_hbuffer *h_val; + duk_uint_t offset; + duk_uint_t length; + + /* XXX: function flag to make this automatic? */ + if (!duk_is_constructor_call(ctx)) { + return DUK_RET_TYPE_ERROR; + } + + h_bufarg = duk__require_bufobj_value(ctx, 0); + DUK_ASSERT(h_bufarg != NULL); + + duk__resolve_offset_opt_length(ctx, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/); + DUK_ASSERT(offset <= h_bufarg->length); + DUK_ASSERT(offset + length <= h_bufarg->length); + + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW), + DUK_BIDX_DATAVIEW_PROTOTYPE); + + h_val = h_bufarg->buf; + if (h_val == NULL) { + return DUK_RET_TYPE_ERROR; + } + h_bufobj->buf = h_val; + DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->offset = h_bufarg->offset + offset; + h_bufobj->length = length; + DUK_ASSERT(h_bufobj->shift == 0); + DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8); + h_bufobj->is_view = 1; + + /* The DataView .buffer property is ordinarily set to the argument + * which is an ArrayBuffer. We accept any duk_hbufferobject as + * an argument and .buffer will be set to the argument regardless + * of what it is. This may be a bit confusing if the argument + * is e.g. a DataView or another TypedArray view. + * + * XXX: Copy .buffer property from a DataView/TypedArray argument? + * Create a fresh ArrayBuffer for Duktape.Buffer and Node.js Buffer + * arguments? See: test-bug-dataview-buffer-prop.js. + */ + + duk_dup(ctx, 0); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); + duk_compact(ctx, -1); + + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * ArrayBuffer.isView() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) { + duk_hobject *h_obj; + duk_bool_t ret = 0; + + h_obj = duk_get_hobject(ctx, 0); + if (h_obj != NULL && DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) { + ret = ((duk_hbufferobject *) h_obj)->is_view; + } + duk_push_boolean(ctx, ret); + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer: toString([encoding], [start], [end]) + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) { + duk_hthread *thr; + duk_hbufferobject *h_this; + duk_int_t start_offset, end_offset; + duk_uint8_t *buf_slice; + duk_size_t slice_length; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + h_this = duk__get_bufobj_this(ctx); + if (h_this == NULL) { + /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */ + duk_push_string(ctx, "[object Object]"); + return 1; + } + DUK_ASSERT_HBUFFEROBJECT_VALID(h_this); + + /* ignore encoding for now */ + + duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &start_offset, &end_offset); + + slice_length = (duk_size_t) (end_offset - start_offset); + buf_slice = (duk_uint8_t *) duk_push_fixed_buffer(ctx, slice_length); + DUK_ASSERT(buf_slice != NULL); + + if (h_this->buf == NULL) { + goto type_error; + } + + if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) { + DUK_MEMCPY((void *) buf_slice, + (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset), + (size_t) slice_length); + } else { + /* not covered, return all zeroes */ + ; + } + + duk_to_string(ctx, -1); + return 1; + + type_error: + return DUK_RET_TYPE_ERROR; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Duktape.Buffer: toString(), valueOf() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv; + duk_small_int_t to_string = duk_get_current_magic(ctx); + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + tv = duk_get_borrowed_this_tval(ctx); + DUK_ASSERT(tv != NULL); + + if (DUK_TVAL_IS_BUFFER(tv)) { + duk_hbuffer *h_buf; + h_buf = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h_buf != NULL); + duk_push_hbuffer(ctx, h_buf); + } else if (DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *h; + duk_hbufferobject *h_bufobj; + + /* Accept any duk_hbufferobject, though we're only normally + * called for Duktape.Buffer values. + */ + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + if (!DUK_HOBJECT_IS_BUFFEROBJECT(h)) { + DUK_DD(DUK_DDPRINT("toString/valueOf() called for a non-bufferobject object")); + goto type_error; + } + h_bufobj = (duk_hbufferobject *) h; + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + if (h_bufobj->buf == NULL) { + DUK_DD(DUK_DDPRINT("toString/valueOf() called for a bufferobject with NULL buf")); + goto type_error; + } + duk_push_hbuffer(ctx, h_bufobj->buf); + } else { + goto type_error; + } + + if (to_string) { + duk_to_string(ctx, -1); + } + return 1; + + type_error: + return DUK_RET_TYPE_ERROR; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.prototype: toJSON() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) { + duk_hthread *thr; + duk_hbufferobject *h_this; + duk_uint8_t *buf; + duk_uint_t i; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + h_this = duk__require_bufobj_this(ctx); + DUK_ASSERT(h_this != NULL); + + if (h_this->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) { + /* Serialize uncovered backing buffer as a null; doesn't + * really matter as long we're memory safe. + */ + duk_push_null(ctx); + return 1; + } + + duk_push_object(ctx); + duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_BUFFER); + duk_put_prop_stridx(ctx, -2, DUK_STRIDX_TYPE); + + duk_push_array(ctx); + for (i = 0; i < h_this->length; i++) { + /* XXX: regetting the pointer may be overkill - we're writing + * to a side-effect free array here. + */ + DUK_ASSERT(h_this->buf != NULL); + buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this); + duk_push_uint(ctx, (duk_uint_t) buf[i]); + duk_put_prop_index(ctx, -2, (duk_idx_t) i); + } + duk_put_prop_stridx(ctx, -2, DUK_STRIDX_DATA); + + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.prototype.equals() + * Node.js Buffer.prototype.compare() + * Node.js Buffer.compare() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) { + duk_hthread *thr; + duk_small_uint_t magic; + duk_hbufferobject *h_bufarg1; + duk_hbufferobject *h_bufarg2; + duk_small_int_t comp_res; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + magic = duk_get_current_magic(ctx); + if (magic & 0x02) { + /* Static call style. */ + h_bufarg1 = duk__require_bufobj_value(ctx, 0); + h_bufarg2 = duk__require_bufobj_value(ctx, 1); + } else { + h_bufarg1 = duk__require_bufobj_this(ctx); + h_bufarg2 = duk__require_bufobj_value(ctx, 0); + } + DUK_ASSERT(h_bufarg1 != NULL); + DUK_ASSERT(h_bufarg2 != NULL); + + /* We want to compare the slice/view areas of the arguments. + * If either slice/view is invalid (underlying buffer is shorter) + * ensure equals() is false, but otherwise the only thing that + * matters is to be memory safe. + */ + + if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg1) && + DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg2)) { + comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset, + (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset, + (duk_size_t) h_bufarg1->length, + (duk_size_t) h_bufarg2->length); + } else { + comp_res = -1; /* either nonzero value is ok */ + } + + if (magic & 0x01) { + /* compare: similar to string comparison but for buffer data. */ + duk_push_int(ctx, comp_res); + } else { + /* equals */ + duk_push_boolean(ctx, (comp_res == 0)); + } + + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.prototype.fill() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) { + duk_hthread *thr; + duk_hbufferobject *h_this; + const duk_uint8_t *fill_str_ptr; + duk_size_t fill_str_len; + duk_uint8_t fill_value; + duk_int_t fill_offset; + duk_int_t fill_end; + duk_size_t fill_length; + duk_uint8_t *p; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + h_this = duk__require_bufobj_this(ctx); + DUK_ASSERT(h_this != NULL); + if (h_this->buf == NULL) { + return DUK_RET_TYPE_ERROR; + } + + /* [ value offset end ] */ + + if (duk_is_string(ctx, 0)) { + fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &fill_str_len); + DUK_ASSERT(fill_str_ptr != NULL); + } else { + fill_value = (duk_uint8_t) duk_to_uint32(ctx, 0); + fill_str_ptr = (const duk_uint8_t *) &fill_value; + fill_str_len = 1; + } + + /* Fill offset handling is more lenient than in Node.js. */ + + duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &fill_offset, &fill_end); + + DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld", + (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length)); + + DUK_ASSERT(fill_end - fill_offset >= 0); + DUK_ASSERT(h_this->buf != NULL); + + p = (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + fill_offset); + fill_length = (duk_size_t) (fill_end - fill_offset); + if (fill_str_len == 1) { + /* Handle single character fills as memset() even when + * the fill data comes from a one-char argument. + */ + DUK_MEMSET((void *) p, (int) fill_str_ptr[0], (size_t) fill_length); + } else if (fill_str_len > 1) { + duk_size_t i, n, t; + + for (i = 0, n = (fill_end - fill_offset), t = 0; i < n; i++) { + p[i] = fill_str_ptr[t++]; + if (t >= fill_str_len) { + t = 0; + } + } + } else { + DUK_DDD(DUK_DDDPRINT("zero size fill pattern, ignore silently")); + } + + /* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */ + duk_push_this(ctx); + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.prototype.write(string, [offset], [length], [encoding]) + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) { + duk_hthread *thr; + duk_hbufferobject *h_this; + duk_uint_t offset; + duk_uint_t length; + const duk_uint8_t *str_data; + duk_size_t str_len; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + h_this = duk__require_bufobj_this(ctx); + DUK_ASSERT(h_this != NULL); + + /* Argument must be a string, e.g. a buffer is not allowed. */ + str_data = (const duk_uint8_t *) duk_require_lstring(ctx, 0, &str_len); + + duk__resolve_offset_opt_length(ctx, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/); + DUK_ASSERT(offset <= h_this->length); + DUK_ASSERT(offset + length <= h_this->length); + + /* XXX: encoding is ignored now. */ + + if (length > str_len) { + length = (duk_uint_t) str_len; + } + + if (DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) { + /* Cannot overlap. */ + DUK_MEMCPY((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset), + (const void *) str_data, + (size_t) length); + } else { + DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore")); + } + + duk_push_uint(ctx, length); + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.prototype.copy() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) { + duk_hthread *thr; + duk_hbufferobject *h_this; + duk_hbufferobject *h_bufarg; + duk_int_t source_length; + duk_int_t target_length; + duk_int_t target_start, source_start, source_end; + duk_uint_t target_ustart, source_ustart, source_uend; + duk_uint_t copy_size = 0; + + /* [ targetBuffer targetStart sourceStart sourceEnd ] */ + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + h_this = duk__require_bufobj_this(ctx); + h_bufarg = duk__require_bufobj_value(ctx, 0); + DUK_ASSERT(h_this != NULL); + DUK_ASSERT(h_bufarg != NULL); + source_length = (duk_int_t) h_this->length; + target_length = (duk_int_t) h_bufarg->length; + + target_start = duk_to_int(ctx, 1); + source_start = duk_to_int(ctx, 2); + if (duk_is_undefined(ctx, 3)) { + source_end = source_length; + } else { + source_end = duk_to_int(ctx, 3); + } + + DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, " + "source_start=%ld, source_end=%ld, source_length=%ld", + (long) target_start, (long) h_bufarg->length, + (long) source_start, (long) source_end, (long) source_length)); + + /* This behavior mostly mimics Node.js now. */ + + if (source_start < 0 || source_end < 0 || target_start < 0) { + /* Negative offsets cause a RangeError. */ + goto fail_bounds; + } + source_ustart = (duk_uint_t) source_start; + source_uend = (duk_uint_t) source_end; + target_ustart = (duk_uint_t) target_start; + if (source_ustart >= source_uend || /* crossed offsets or zero size */ + source_ustart >= (duk_uint_t) source_length || /* source out-of-bounds (but positive) */ + target_ustart >= (duk_uint_t) target_length) { /* target out-of-bounds (but positive) */ + goto silent_ignore; + } + if (source_uend >= (duk_uint_t) source_length) { + /* Source end clamped silently to available length. */ + source_uend = source_length; + } + copy_size = source_uend - source_ustart; + if (target_ustart + copy_size > (duk_uint_t) target_length) { + /* Clamp to target's end if too long. + * + * NOTE: there's no overflow possibility in the comparison; + * both target_ustart and copy_size are >= 0 and based on + * values in duk_int_t range. Adding them as duk_uint_t + * values is then guaranteed not to overflow. + */ + DUK_ASSERT(target_ustart + copy_size >= target_ustart); /* no overflow */ + DUK_ASSERT(target_ustart + copy_size >= copy_size); /* no overflow */ + copy_size = (duk_uint_t) target_length - target_ustart; + } + + DUK_DDD(DUK_DDDPRINT("making copy: target_ustart=%lu source_ustart=%lu copy_size=%lu", + (unsigned long) target_ustart, (unsigned long) source_ustart, + (unsigned long) copy_size)); + + DUK_ASSERT(copy_size >= 1); + DUK_ASSERT(source_ustart <= (duk_uint_t) source_length); + DUK_ASSERT(source_ustart + copy_size <= (duk_uint_t) source_length); + DUK_ASSERT(target_ustart <= (duk_uint_t) target_length); + DUK_ASSERT(target_ustart + copy_size <= (duk_uint_t) target_length); + + /* Ensure copy is covered by underlying buffers. */ + DUK_ASSERT(h_bufarg->buf != NULL); /* length check */ + DUK_ASSERT(h_this->buf != NULL); /* length check */ + if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) && + DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) { + /* Must use memmove() because copy area may overlap (source and target + * buffer may be the same, or from different slices. + */ + DUK_MEMMOVE((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart), + (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + source_ustart), + (size_t) copy_size); + } else { + DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring")); + } + + silent_ignore: + /* Return value is like write(), number of bytes written. + * The return value matters because of code like: + * "off += buf.copy(...)". + */ + duk_push_uint(ctx, copy_size); + return 1; + + fail_bounds: + return DUK_RET_RANGE_ERROR; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * TypedArray.prototype.set() + * + * TypedArray set() is pretty interesting to implement because: + * + * - The source argument may be a plain array or a typedarray. If the + * source is a TypedArray, values are decoded and re-encoded into the + * target (not as a plain byte copy). This may happen even when the + * element byte size is the same, e.g. integer values may be re-encoded + * into floats. + * + * - Source and target may refer to the same underlying buffer, so that + * the set() operation may overlap. The specification requires that this + * must work as if a copy was made before the operation. Note that this + * is NOT a simple memmove() situation because the source and target + * byte sizes may be different -- e.g. a 4-byte source (Int8Array) may + * expand to a 16-byte target (Uint32Array) so that the target overlaps + * the source both from beginning and the end (unlike in typical memmove). + * + * - Even if 'buf' pointers of the source and target differ, there's no + * guarantee that their memory areas don't overlap. This may be the + * case with external buffers. + * + * Even so, it is nice to optimize for the common case: + * + * - Source and target separate buffers or non-overlapping. + * + * - Source and target have a compatible type so that a plain byte copy + * is possible. Note that while e.g. uint8 and int8 are compatible + * (coercion one way or another doesn't change the byte representation), + * e.g. int8 and uint8clamped are NOT compatible when writing int8 + * values into uint8clamped typedarray (-1 would clamp to 0 for instance). + * + * See test-bi-typedarray-proto-set.js. + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { + duk_hthread *thr; + duk_hbufferobject *h_this; + duk_hobject *h_obj; + duk_uarridx_t i, n; + duk_int_t offset_signed; + duk_uint_t offset_elems; + duk_uint_t offset_bytes; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + h_this = duk__require_bufobj_this(ctx); + DUK_ASSERT(h_this != NULL); + DUK_ASSERT_HBUFFEROBJECT_VALID(h_this); + + if (h_this->buf == NULL) { + DUK_DDD(DUK_DDDPRINT("source neutered, skip copy")); + return 0; + } + + h_obj = duk_require_hobject(ctx, 0); + DUK_ASSERT(h_obj != NULL); + + /* XXX: V8 throws a TypeError for negative values. Would it + * be more useful to interpret negative offsets here from the + * end of the buffer too? + */ + offset_signed = duk_to_int(ctx, 1); + if (offset_signed < 0) { + return DUK_RET_TYPE_ERROR; + } + offset_elems = (duk_uint_t) offset_signed; + offset_bytes = offset_elems << h_this->shift; + if ((offset_bytes >> h_this->shift) != offset_elems) { + /* Byte length would overflow. */ + /* XXX: easier check with less code? */ + return DUK_RET_RANGE_ERROR; + } + if (offset_bytes > h_this->length) { + /* Equality may be OK but >length not. Checking + * this explicitly avoids some overflow cases + * below. + */ + return DUK_RET_RANGE_ERROR; + } + DUK_ASSERT(offset_bytes <= h_this->length); + + /* Fast path: source is a TypedArray (or any bufferobject). */ + + if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) { + duk_hbufferobject *h_bufarg; + duk_uint16_t comp_mask; + duk_small_int_t no_overlap = 0; + duk_uint_t src_length; + duk_uint_t dst_length; + duk_uint_t dst_length_elems; + duk_uint8_t *p_src_base; + duk_uint8_t *p_src_end; + duk_uint8_t *p_src; + duk_uint8_t *p_dst_base; + duk_uint8_t *p_dst; + duk_small_uint_t src_elem_size; + duk_small_uint_t dst_elem_size; + + h_bufarg = (duk_hbufferobject *) h_obj; + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg); + + if (h_bufarg->buf == NULL) { + DUK_DDD(DUK_DDDPRINT("target neutered, skip copy")); + return 0; + } + + /* Nominal size check. */ + src_length = h_bufarg->length; /* bytes in source */ + dst_length_elems = (src_length >> h_bufarg->shift); /* elems in source and dest */ + dst_length = dst_length_elems << h_this->shift; /* bytes in dest */ + if ((dst_length >> h_this->shift) != dst_length_elems) { + /* Byte length would overflow. */ + /* XXX: easier check with less code? */ + return DUK_RET_RANGE_ERROR; + } + DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld", + (long) src_length, (long) dst_length)); + DUK_ASSERT(offset_bytes <= h_this->length); + if (dst_length > h_this->length - offset_bytes) { + /* Overflow not an issue because subtraction is used on the right + * side and guaranteed to be >= 0. + */ + DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length")); + return DUK_RET_RANGE_ERROR; + } + if (!DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) { + DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore")); + return 0; + } + + p_src_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg); + p_dst_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes; + + /* Check actual underlying buffers for validity and that they + * cover the copy. No side effects are allowed after the check + * so that the validity status doesn't change. + */ + if (!DUK_HBUFFEROBJECT_VALID_SLICE(h_this) || + !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) { + /* The condition could be more narrow and check for the + * copy area only, but there's no need for fine grained + * behavior when the underlying buffer is misconfigured. + */ + DUK_DDD(DUK_DDDPRINT("source and/or target not covered by underlying buffer, skip copy")); + return 0; + } + + /* We want to do a straight memory copy if possible: this is + * an important operation because .set() is the TypedArray + * way to copy chunks of memory. However, because set() + * conceptually works in terms of elements, not all views are + * compatible with direct byte copying. + * + * If we do manage a direct copy, the "overlap issue" handled + * below can just be solved using memmove() because the source + * and destination element sizes are necessarily equal. + */ + + DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t)); + comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type]; + if (comp_mask & (1 << h_bufarg->elem_type)) { + DUK_ASSERT(src_length == dst_length); + + DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible")); + DUK_MEMMOVE((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length); + return 0; + } + DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item")); + + /* We want to avoid making a copy to process set() but that's + * not always possible: the source and the target may overlap + * and because element sizes are different, the overlap cannot + * always be handled with a memmove() or choosing the copy + * direction in a certain way. For example, if source type is + * uint8 and target type is uint32, the target area may exceed + * the source area from both ends! + * + * Note that because external buffers may point to the same + * memory areas, we must ultimately make this check using + * pointers. + * + * NOTE: careful with side effects: any side effect may cause + * a buffer resize (or external buffer pointer/length update)! + */ + + DUK_DDD(DUK_DDDPRINT("overlap check: p_src_base=%p, src_length=%ld, " + "p_dst_base=%p, dst_length=%ld", + (void *) p_src_base, (long) src_length, + (void *) p_dst_base, (long) dst_length)); + + if (p_src_base >= p_dst_base + dst_length || /* source starts after dest ends */ + p_src_base + src_length <= p_dst_base) { /* source ends before dest starts */ + no_overlap = 1; + } + + if (!no_overlap) { + /* There's overlap: the desired end result is that + * conceptually a copy is made to avoid "trampling" + * of source data by destination writes. We make + * an actual temporary copy to handle this case. + */ + duk_uint8_t *p_src_copy; + + DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source")); + p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_length); + DUK_ASSERT(p_src_copy != NULL); + DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length); + + p_src_base = p_src_copy; /* use p_src_base from now on */ + } + /* Value stack intentionally mixed size here. */ + + DUK_DDD(DUK_DDDPRINT("after overlap check: p_src_base=%p, src_length=%ld, " + "p_dst_base=%p, dst_length=%ld, valstack top=%ld", + (void *) p_src_base, (long) src_length, + (void *) p_dst_base, (long) dst_length, + (long) duk_get_top(ctx))); + + /* Ready to make the copy. We must proceed element by element + * and must avoid any side effects that might cause the buffer + * validity check above to become invalid. + * + * Although we work through the value stack here, only plain + * numbers are handled which should be side effect safe. + */ + + src_elem_size = 1 << h_bufarg->shift; + dst_elem_size = 1 << h_this->shift; + p_src = p_src_base; + p_dst = p_dst_base; + p_src_end = p_src_base + src_length; + + while (p_src != p_src_end) { + DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: " + "p_src=%p, p_src_end=%p, p_dst=%p", + (void *) p_src, (void *) p_src_end, (void *) p_dst)); + /* A validated read() is always a number, so it's write coercion + * is always side effect free an won't invalidate pointers etc. + */ + duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size); + duk_hbufferobject_validated_write(ctx, h_this, p_dst, dst_elem_size); + duk_pop(ctx); + p_src += src_elem_size; + p_dst += dst_elem_size; + } + + return 0; + } else { + /* Slow path: quite slow, but we save space by using the property code + * to write coerce target values. We don't need to worry about overlap + * here because the source is not a TypedArray. + * + * We could use the bufferobject write coercion helper but since the + * property read may have arbitrary side effects, full validity checks + * would be needed for every element anyway. + */ + + n = (duk_uarridx_t) duk_get_length(ctx, 0); + DUK_ASSERT(offset_bytes <= h_this->length); + if ((n << h_this->shift) > h_this->length - offset_bytes) { + /* Overflow not an issue because subtraction is used on the right + * side and guaranteed to be >= 0. + */ + DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length")); + return DUK_RET_RANGE_ERROR; + } + + /* There's no need to check for buffer validity status for the + * target here: the property access code will do that for each + * element. Moreover, if we did check the validity here, side + * effects from reading the source argument might invalidate + * the results anyway. + */ + + DUK_ASSERT_TOP(ctx, 2); + duk_push_this(ctx); + + for (i = 0; i < n; i++) { + duk_get_prop_index(ctx, 0, i); + duk_put_prop_index(ctx, 2, offset_elems + i); + } + } + + return 0; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.prototype.slice([start], [end]) + * ArrayBuffer.prototype.slice(begin, [end]) + * TypedArray.prototype.slice(begin, [end]) + * + * The API calls are almost identical; negative indices are counted from end + * of buffer, and final indices are clamped (allowing crossed indices). Main + * differences: + * + * - Copy/view behavior; Node.js .slice() and TypedArray .subarray() create + * views, ArrayBuffer .slice() creates a copy + * + * - Resulting object has a different class and prototype depending on the + * call (or 'this' argument) + * + * - TypedArray .subarray() arguments are element indices, not byte offsets + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) { + duk_hthread *thr; + duk_small_int_t magic; + duk_small_uint_t res_class_num; + duk_hobject *res_proto; + duk_hbufferobject *h_this; + duk_hbufferobject *h_bufobj; + duk_hbuffer *h_val; + duk_int_t start_offset, end_offset; + duk_uint_t slice_length; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + /* [ start end ] */ + + magic = duk_get_current_magic(ctx); + h_this = duk__require_bufobj_this(ctx); + + /* Slice offsets are element (not byte) offsets, which only matters + * for TypedArray views, Node.js Buffer and ArrayBuffer have shift + * zero so byte and element offsets are the same. Negative indices + * are counted from end of slice, crossed indices are allowed (and + * result in zero length result), and final values are clamped + * against the current slice. There's intentionally no check + * against the underlying buffer here. + */ + + duk__clamp_startend_negidx_shifted(ctx, h_this, 0 /*idx_start*/, 1 /*idx_end*/, &start_offset, &end_offset); + DUK_ASSERT(end_offset >= start_offset); + slice_length = (duk_uint_t) (end_offset - start_offset); + + /* The resulting buffer object gets the same class and prototype as + * the buffer in 'this', e.g. if the input is a Node.js Buffer the + * result is a Node.js Buffer; if the input is a Float32Array, the + * result is a Float32Array. + * + * For the class number this seems correct. The internal prototype + * is not so clear: if 'this' is a bufferobject with a non-standard + * prototype object, that value gets copied over into the result + * (instead of using the standard prototype for that object type). + */ + + res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this); + h_bufobj = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num), + DUK_BIDX_OBJECT_PROTOTYPE); /* replaced */ + DUK_ASSERT(h_bufobj != NULL); + res_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_this); /* may be NULL */ + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_bufobj, res_proto); + + h_bufobj->length = slice_length; + h_bufobj->shift = h_this->shift; /* inherit */ + h_bufobj->elem_type = h_this->elem_type; /* inherit */ + h_bufobj->is_view = magic & 0x01; + DUK_ASSERT(h_bufobj->is_view == 0 || h_bufobj->is_view == 1); + + h_val = h_this->buf; + if (h_val == NULL) { + return DUK_RET_TYPE_ERROR; + } + + if (magic & 0x02) { + /* non-zero: make copy */ + duk_uint8_t *p_copy; + duk_size_t copy_length; + + p_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) slice_length); + DUK_ASSERT(p_copy != NULL); + + /* Copy slice, respecting underlying buffer limits; remainder + * is left as zero. + */ + copy_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, slice_length); + DUK_MEMCPY((void *) p_copy, + (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset), + copy_length); + + h_val = duk_get_hbuffer(ctx, -1); + DUK_ASSERT(h_val != NULL); + + h_bufobj->buf = h_val; + DUK_HBUFFER_INCREF(thr, h_val); + DUK_ASSERT(h_bufobj->offset == 0); + + duk_pop(ctx); /* reachable so pop OK */ + } else { + h_bufobj->buf = h_val; + DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset); + + /* Copy the .buffer property, needed for TypedArray.prototype.subarray(). + * + * XXX: limit copy only for TypedArray classes specifically? + */ + + duk_push_this(ctx); + if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_BUFFER)) { + duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE); + duk_pop(ctx); + } else { + duk_pop_2(ctx); + } + } + /* unbalanced stack on purpose */ + + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.isEncoding() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) { + const char *encoding; + + /* only accept lowercase 'utf8' now. */ + + encoding = duk_to_string(ctx, 0); + DUK_ASSERT(duk_is_string(ctx, 0)); /* guaranteed by duk_to_string() */ + duk_push_boolean(ctx, DUK_STRCMP(encoding, "utf8") == 0); + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.isBuffer() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) { + duk_hthread *thr; + duk_tval *tv; + duk_hobject *h; + duk_hobject *h_proto; + duk_bool_t ret = 0; + + thr = (duk_hthread *) ctx; + + DUK_ASSERT(duk_get_top(ctx) >= 1); /* nargs */ + tv = duk_get_tval(ctx, 0); + DUK_ASSERT(tv != NULL); + + if (DUK_TVAL_IS_OBJECT(tv)) { + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + + h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE]; + DUK_ASSERT(h_proto != NULL); + + h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); + if (h) { + ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/); + } + } + + duk_push_boolean(ctx, ret); + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.byteLength() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) { + const char *str; + duk_size_t len; + + /* At the moment Buffer() will just use the string bytes as + * is (ignoring encoding), so we return the string length here + * unconditionally. + */ + + str = duk_to_lstring(ctx, 0, &len); + DUK_UNREF(str); + duk_push_size_t(ctx, len); + return 1; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Node.js Buffer.concat() + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) { + duk_hthread *thr; + duk_hobject *h_arg; + duk_int_t total_length = 0; + duk_hbufferobject *h_bufobj; + duk_hbufferobject *h_bufres; + duk_hbuffer *h_val; + duk_uint_t i, n; + duk_uint8_t *p; + duk_size_t space_left; + duk_size_t copy_size; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + /* Node.js accepts only actual Arrays. */ + h_arg = duk_require_hobject(ctx, 0); + if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) { + return DUK_RET_TYPE_ERROR; + } + + /* Compute result length and validate argument buffers. */ + n = (duk_uint_t) duk_get_length(ctx, 0); + for (i = 0; i < n; i++) { + /* Neutered checks not necessary here: neutered buffers have + * zero 'length' so we'll effectively skip them. + */ + DUK_ASSERT_TOP(ctx, 2); /* [ array totalLength ] */ + duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */ + h_bufobj = duk__require_bufobj_value(ctx, 2); + DUK_ASSERT(h_bufobj != NULL); + total_length += h_bufobj->length; + duk_pop(ctx); + } + if (n == 1) { + /* For the case n==1 Node.js doesn't seem to type check + * the sole member but we do it before returning it. + * For this case only the original buffer object is + * returned (not a copy). + */ + duk_get_prop_index(ctx, 0, 0); + return 1; + } + + /* User totalLength overrides a computed length, but we'll check + * every copy in the copy loop. Note that duk_to_uint() can + * technically have arbitrary side effects so we need to recheck + * the buffers in the copy loop. + */ + if (!duk_is_undefined(ctx, 1) && n > 0) { + /* For n == 0, Node.js ignores totalLength argument and + * returns a zero length buffer. + */ + total_length = duk_to_int(ctx, 1); + } + if (total_length < 0) { + return DUK_RET_RANGE_ERROR; + } + + h_bufres = duk_push_bufferobject_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFFEROBJECT | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER), + DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); + DUK_ASSERT(h_bufres != NULL); + + p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, total_length); + DUK_ASSERT(p != NULL); + space_left = total_length; + + for (i = 0; i < n; i++) { + DUK_ASSERT_TOP(ctx, 4); /* [ array totalLength bufres buf ] */ + + duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); + h_bufobj = duk__require_bufobj_value(ctx, 4); + DUK_ASSERT(h_bufobj != NULL); + + copy_size = h_bufobj->length; + if (copy_size > space_left) { + copy_size = space_left; + } + + if (h_bufobj->buf != NULL && + DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) { + DUK_MEMCPY((void *) p, + (const void *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj), + copy_size); + } else { + /* Just skip, leaving zeroes in the result. */ + ; + } + p += copy_size; + space_left -= copy_size; + + duk_pop(ctx); + } + + h_val = duk_get_hbuffer(ctx, -1); + DUK_ASSERT(h_val != NULL); + + duk__set_bufobj_buffer(ctx, h_bufres, h_val); + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufres); + + duk_pop(ctx); /* pop plain buffer, now reachable through h_bufres */ + + return 1; /* return h_bufres */ +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +/* + * Shared readfield and writefield methods + * + * The readfield/writefield methods need support for endianness and field + * types. All offsets are byte based so no offset shifting is needed. + */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* Format of magic, bits: + * 0...1: field type; 0=uint8, 1=uint16, 2=uint32, 3=float, 4=double, 5=unused, 6=unused, 7=unused + * 3: endianness: 0=little, 1=big + * 4: signed: 1=yes, 0=no + * 5: typedarray: 1=yes, 0=no + */ +#define DUK__FLD_8BIT 0 +#define DUK__FLD_16BIT 1 +#define DUK__FLD_32BIT 2 +#define DUK__FLD_FLOAT 3 +#define DUK__FLD_DOUBLE 4 +#define DUK__FLD_VARINT 5 +#define DUK__FLD_BIGENDIAN (1 << 3) +#define DUK__FLD_SIGNED (1 << 4) +#define DUK__FLD_TYPEDARRAY (1 << 5) + +/* XXX: split into separate functions for each field type? */ +DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) { + duk_hthread *thr; + duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx); + duk_small_int_t magic_ftype; + duk_small_int_t magic_bigendian; + duk_small_int_t magic_signed; + duk_small_int_t magic_typedarray; + duk_small_int_t endswap; + duk_hbufferobject *h_this; + duk_bool_t no_assert; + duk_int_t offset_signed; + duk_uint_t offset; + duk_uint_t buffer_length; + duk_uint_t check_length; + duk_uint8_t *buf; + duk_double_union du; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + magic_ftype = magic & 0x0007; + magic_bigendian = magic & 0x0008; + magic_signed = magic & 0x0010; + magic_typedarray = magic & 0x0020; + + h_this = duk__require_bufobj_this(ctx); + DUK_ASSERT(h_this != NULL); + buffer_length = h_this->length; + + /* [ offset noAssert ], when ftype != DUK__FLD_VARINT */ + /* [ offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */ + /* [ offset littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */ + + /* Handle TypedArray vs. Node.js Buffer arg differences */ + if (magic_typedarray) { + no_assert = 0; +#if defined(DUK_USE_INTEGER_LE) + endswap = !duk_to_boolean(ctx, 1); /* 1=little endian */ +#else + endswap = duk_to_boolean(ctx, 1); /* 1=little endian */ +#endif + } else { + no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1); +#if defined(DUK_USE_INTEGER_LE) + endswap = magic_bigendian; +#else + endswap = !magic_bigendian; +#endif + } + + /* Offset is coerced first to signed integer range and then to unsigned. + * This ensures we can add a small byte length (1-8) to the offset in + * bound checks and not wrap. + */ + offset_signed = duk_to_int(ctx, 0); + offset = (duk_uint_t) offset_signed; + if (offset_signed < 0) { + goto fail_bounds; + } + + DUK_DDD(DUK_DDDPRINT("readfield, buffer_length=%ld, offset=%ld, no_assert=%d, " + "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, " + "endswap=%d", + (long) buffer_length, (long) offset, (int) no_assert, + (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3), + (int) (magic_signed >> 4), (int) endswap)); + + /* Update 'buffer_length' to be the effective, safe limit which + * takes into account the underlying buffer. This value will be + * potentially invalidated by any side effect. + */ + check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length); + DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld", + (long) buffer_length, (long) check_length)); + + if (h_this->buf) { + buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this); + } else { + /* Neutered. We could go into the switch-case safely with + * buf == NULL because check_length == 0. To avoid scanbuild + * warnings, fail directly instead. + */ + DUK_ASSERT(check_length == 0); + goto fail_neutered; + } + DUK_ASSERT(buf != NULL); + + switch (magic_ftype) { + case DUK__FLD_8BIT: { + duk_uint8_t tmp; + if (offset + 1U > check_length) { + goto fail_bounds; + } + tmp = buf[offset]; + if (magic_signed) { + duk_push_int(ctx, (duk_int_t) ((duk_int8_t) tmp)); + } else { + duk_push_uint(ctx, (duk_uint_t) tmp); + } + break; + } + case DUK__FLD_16BIT: { + duk_uint16_t tmp; + if (offset + 2U > check_length) { + goto fail_bounds; + } + DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 2); + tmp = du.us[0]; + if (endswap) { + tmp = DUK_BSWAP16(tmp); + } + if (magic_signed) { + duk_push_int(ctx, (duk_int_t) ((duk_int16_t) tmp)); + } else { + duk_push_uint(ctx, (duk_uint_t) tmp); + } + break; + } + case DUK__FLD_32BIT: { + duk_uint32_t tmp; + if (offset + 4U > check_length) { + goto fail_bounds; + } + DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4); + tmp = du.ui[0]; + if (endswap) { + tmp = DUK_BSWAP32(tmp); + } + if (magic_signed) { + duk_push_int(ctx, (duk_int_t) ((duk_int32_t) tmp)); + } else { + duk_push_uint(ctx, (duk_uint_t) tmp); + } + break; + } + case DUK__FLD_FLOAT: { + duk_uint32_t tmp; + if (offset + 4U > check_length) { + goto fail_bounds; + } + DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4); + if (endswap) { + tmp = du.ui[0]; + tmp = DUK_BSWAP32(tmp); + du.ui[0] = tmp; + } + duk_push_number(ctx, (duk_double_t) du.f[0]); + break; + } + case DUK__FLD_DOUBLE: { + if (offset + 8U > check_length) { + goto fail_bounds; + } + DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 8); + if (endswap) { + DUK_DBLUNION_BSWAP64(&du); + } + duk_push_number(ctx, (duk_double_t) du.d); + break; + } + case DUK__FLD_VARINT: { + /* Node.js Buffer variable width integer field. We don't really + * care about speed here, so aim for shortest algorithm. + */ + duk_int_t field_bytelen; + duk_int_t i, i_step, i_end; +#if defined(DUK_USE_64BIT_OPS) + duk_int64_t tmp; + duk_small_uint_t shift_tmp; +#else + duk_double_t tmp; + duk_small_int_t highbyte; +#endif + const duk_uint8_t *p; + + field_bytelen = duk_get_int(ctx, 1); /* avoid side effects! */ + if (field_bytelen < 1 || field_bytelen > 6) { + goto fail_field_length; + } + if (offset + (duk_uint_t) field_bytelen > check_length) { + goto fail_bounds; + } + p = (const duk_uint8_t *) (buf + offset); + + /* Slow gathering of value using either 64-bit arithmetic + * or IEEE doubles if 64-bit types not available. Handling + * of negative numbers is a bit non-obvious in both cases. + */ + + if (magic_bigendian) { + /* Gather in big endian */ + i = 0; + i_step = 1; + i_end = field_bytelen; /* one i_step over */ + } else { + /* Gather in little endian */ + i = field_bytelen - 1; + i_step = -1; + i_end = -1; /* one i_step over */ + } + +#if defined(DUK_USE_64BIT_OPS) + tmp = 0; + do { + DUK_ASSERT(i >= 0 && i < field_bytelen); + tmp = (tmp << 8) + (duk_int64_t) p[i]; + i += i_step; + } while (i != i_end); + + if (magic_signed) { + /* Shift to sign extend. */ + shift_tmp = 64 - (field_bytelen * 8); + tmp = (tmp << shift_tmp) >> shift_tmp; + } + + duk_push_i64(ctx, tmp); +#else + highbyte = p[i]; + if (magic_signed && (highbyte & 0x80) != 0) { + /* 0xff => 255 - 256 = -1; 0x80 => 128 - 256 = -128 */ + tmp = (duk_double_t) (highbyte - 256); + } else { + tmp = (duk_double_t) highbyte; + } + for (;;) { + i += i_step; + if (i == i_end) { + break; + } + DUK_ASSERT(i >= 0 && i < field_bytelen); + tmp = (tmp * 256.0) + (duk_double_t) p[i]; + } + + duk_push_number(ctx, tmp); +#endif + break; + } + default: { /* should never happen but default here */ + goto fail_bounds; + } + } + + return 1; + + fail_neutered: + fail_field_length: + fail_bounds: + if (no_assert) { + /* Node.js return value for noAssert out-of-bounds reads is + * usually (but not always) NaN. Return NaN consistently. + */ + duk_push_nan(ctx); + return 1; + } + + return DUK_RET_RANGE_ERROR; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +/* XXX: split into separate functions for each field type? */ +DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) { + duk_hthread *thr; + duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx); + duk_small_int_t magic_ftype; + duk_small_int_t magic_bigendian; + duk_small_int_t magic_signed; + duk_small_int_t magic_typedarray; + duk_small_int_t endswap; + duk_hbufferobject *h_this; + duk_bool_t no_assert; + duk_int_t offset_signed; + duk_uint_t offset; + duk_uint_t buffer_length; + duk_uint_t check_length; + duk_uint8_t *buf; + duk_double_union du; + duk_int_t nbytes = 0; + + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + magic_ftype = magic & 0x0007; + magic_bigendian = magic & 0x0008; + magic_signed = magic & 0x0010; + magic_typedarray = magic & 0x0020; + DUK_UNREF(magic_signed); + + h_this = duk__require_bufobj_this(ctx); + DUK_ASSERT(h_this != NULL); + buffer_length = h_this->length; + + /* [ value offset noAssert ], when ftype != DUK__FLD_VARINT */ + /* [ value offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */ + /* [ offset value littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */ + + /* Handle TypedArray vs. Node.js Buffer arg differences */ + if (magic_typedarray) { + no_assert = 0; +#if defined(DUK_USE_INTEGER_LE) + endswap = !duk_to_boolean(ctx, 2); /* 1=little endian */ +#else + endswap = duk_to_boolean(ctx, 2); /* 1=little endian */ +#endif + duk_swap(ctx, 0, 1); /* offset/value order different from Node.js */ + } else { + no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2); +#if defined(DUK_USE_INTEGER_LE) + endswap = magic_bigendian; +#else + endswap = !magic_bigendian; +#endif + } + + /* Offset is coerced first to signed integer range and then to unsigned. + * This ensures we can add a small byte length (1-8) to the offset in + * bound checks and not wrap. + */ + offset_signed = duk_to_int(ctx, 1); + offset = (duk_uint_t) offset_signed; + + /* We need 'nbytes' even for a failed offset; return value must be + * (offset + nbytes) even when write fails due to invalid offset. + */ + if (magic_ftype != DUK__FLD_VARINT) { + DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t))); + nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype]; + } else { + nbytes = duk_get_int(ctx, 2); + if (nbytes < 1 || nbytes > 6) { + goto fail_field_length; + } + } + DUK_ASSERT(nbytes >= 1 && nbytes <= 8); + + /* Now we can check offset validity. */ + if (offset_signed < 0) { + goto fail_bounds; + } + + DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, " + "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, " + "endswap=%d", + duk_get_tval(ctx, 0), (long) buffer_length, (long) offset, (int) no_assert, + (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3), + (int) (magic_signed >> 4), (int) endswap)); + + /* Coerce value to a number before computing check_length, so that + * the field type specific coercion below can't have side effects + * that would invalidate check_length. + */ + duk_to_number(ctx, 0); + + /* Update 'buffer_length' to be the effective, safe limit which + * takes into account the underlying buffer. This value will be + * potentially invalidated by any side effect. + */ + check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length); + DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld", + (long) buffer_length, (long) check_length)); + + if (h_this->buf) { + buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this); + } else { + /* Neutered. We could go into the switch-case safely with + * buf == NULL because check_length == 0. To avoid scanbuild + * warnings, fail directly instead. + */ + DUK_ASSERT(check_length == 0); + goto fail_neutered; + } + DUK_ASSERT(buf != NULL); + + switch (magic_ftype) { + case DUK__FLD_8BIT: { + if (offset + 1U > check_length) { + goto fail_bounds; + } + /* sign doesn't matter when writing */ + buf[offset] = (duk_uint8_t) duk_to_uint32(ctx, 0); + break; + } + case DUK__FLD_16BIT: { + duk_uint16_t tmp; + if (offset + 2U > check_length) { + goto fail_bounds; + } + tmp = (duk_uint16_t) duk_to_uint32(ctx, 0); + if (endswap) { + tmp = DUK_BSWAP16(tmp); + } + du.us[0] = tmp; + /* sign doesn't matter when writing */ + DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 2); + break; + } + case DUK__FLD_32BIT: { + duk_uint32_t tmp; + if (offset + 4U > check_length) { + goto fail_bounds; + } + tmp = (duk_uint32_t) duk_to_uint32(ctx, 0); + if (endswap) { + tmp = DUK_BSWAP32(tmp); + } + du.ui[0] = tmp; + /* sign doesn't matter when writing */ + DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4); + break; + } + case DUK__FLD_FLOAT: { + duk_uint32_t tmp; + if (offset + 4U > check_length) { + goto fail_bounds; + } + du.f[0] = (duk_float_t) duk_to_number(ctx, 0); + if (endswap) { + tmp = du.ui[0]; + tmp = DUK_BSWAP32(tmp); + du.ui[0] = tmp; + } + /* sign doesn't matter when writing */ + DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4); + break; + } + case DUK__FLD_DOUBLE: { + if (offset + 8U > check_length) { + goto fail_bounds; + } + du.d = (duk_double_t) duk_to_number(ctx, 0); + if (endswap) { + DUK_DBLUNION_BSWAP64(&du); + } + /* sign doesn't matter when writing */ + DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 8); + break; + } + case DUK__FLD_VARINT: { + /* Node.js Buffer variable width integer field. We don't really + * care about speed here, so aim for shortest algorithm. + */ + duk_int_t field_bytelen; + duk_int_t i, i_step, i_end; +#if defined(DUK_USE_64BIT_OPS) + duk_int64_t tmp; +#else + duk_double_t tmp; +#endif + duk_uint8_t *p; + + field_bytelen = (duk_int_t) nbytes; + if (offset + (duk_uint_t) field_bytelen > check_length) { + goto fail_bounds; + } + + /* Slow writing of value using either 64-bit arithmetic + * or IEEE doubles if 64-bit types not available. There's + * no special sign handling when writing varints. + */ + + if (magic_bigendian) { + /* Write in big endian */ + i = field_bytelen; /* one i_step added at top of loop */ + i_step = -1; + i_end = 0; + } else { + /* Write in little endian */ + i = -1; /* one i_step added at top of loop */ + i_step = 1; + i_end = field_bytelen - 1; + } + + /* XXX: The duk_to_number() cast followed by integer coercion + * is platform specific so NaN, +/- Infinity, and out-of-bounds + * values result in platform specific output now. + * See: test-bi-nodejs-buffer-proto-varint-special.js + */ + +#if defined(DUK_USE_64BIT_OPS) + tmp = (duk_int64_t) duk_to_number(ctx, 0); + p = (duk_uint8_t *) (buf + offset); + do { + i += i_step; + DUK_ASSERT(i >= 0 && i < field_bytelen); + p[i] = (duk_uint8_t) (tmp & 0xff); + tmp = tmp >> 8; /* unnecessary shift for last byte */ + } while (i != i_end); +#else + tmp = duk_to_number(ctx, 0); + p = (duk_uint8_t *) (buf + offset); + do { + i += i_step; + tmp = DUK_FLOOR(tmp); + DUK_ASSERT(i >= 0 && i < field_bytelen); + p[i] = (duk_uint8_t) (DUK_FMOD(tmp, 256.0)); + tmp = tmp / 256.0; /* unnecessary div for last byte */ + } while (i != i_end); +#endif + break; + } + default: { /* should never happen but default here */ + goto fail_bounds; + } + } + + /* Node.js Buffer: return offset + #bytes written (i.e. next + * write offset). + */ + if (magic_typedarray) { + /* For TypedArrays 'undefined' return value is specified + * by ES6 (matches V8). + */ + return 0; + } + duk_push_uint(ctx, offset + nbytes); + return 1; + + fail_neutered: + fail_field_length: + fail_bounds: + if (no_assert) { + /* Node.js return value for failed writes is offset + #bytes + * that would have been written. + */ + /* XXX: for negative input offsets, 'offset' will be a large + * positive value so the result here is confusing. + */ + if (magic_typedarray) { + return 0; + } + duk_push_uint(ctx, offset + nbytes); + return 1; + } + return DUK_RET_RANGE_ERROR; +} +#else /* DUK_USE_BUFFEROBJECT_SUPPORT */ +DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + +#undef DUK__FLD_8BIT +#undef DUK__FLD_16BIT +#undef DUK__FLD_32BIT +#undef DUK__FLD_FLOAT +#undef DUK__FLD_DOUBLE +#undef DUK__FLD_VARINT +#undef DUK__FLD_BIGENDIAN +#undef DUK__FLD_SIGNED +#undef DUK__FLD_TYPEDARRAY +/* + * 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 removed: 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; +} +/* + * Unix-like Date providers + * + * Generally useful Unix / POSIX / ANSI Date providers. + */ + +/* include removed: 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 +/* + * Windows Date providers + * + * Platform specific links: + * + * - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx + */ + +/* include removed: 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 */ +/* + * 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 removed: 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 */ +} +/* + * Error built-ins + */ + +/* include removed: duk_internal.h */ + +DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) { + /* Behavior for constructor and non-constructor call is + * the same except for augmenting the created error. When + * called as a constructor, the caller (duk_new()) will handle + * augmentation; when called as normal function, we need to do + * it here. + */ + + duk_hthread *thr = (duk_hthread *) ctx; + duk_small_int_t bidx_prototype = duk_get_current_magic(ctx); + + /* same for both error and each subclass like TypeError */ + duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR); + + DUK_UNREF(thr); + + duk_push_object_helper(ctx, flags_and_class, bidx_prototype); + + /* If message is undefined, the own property 'message' is not set at + * all to save property space. An empty message is inherited anyway. + */ + if (!duk_is_undefined(ctx, 0)) { + duk_to_string(ctx, 0); + duk_dup(ctx, 0); /* [ message error message ] */ + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); + } + + /* Augment the error if called as a normal function. __FILE__ and __LINE__ + * are not desirable in this case. + */ + +#ifdef DUK_USE_AUGMENT_ERROR_CREATE + if (!duk_is_constructor_call(ctx)) { + duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/); + } +#endif + + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) { + /* XXX: optimize with more direct internal access */ + + duk_push_this(ctx); + (void) duk_require_hobject_or_lfunc_coerce(ctx, -1); + + /* [ ... this ] */ + + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); + if (duk_is_undefined(ctx, -1)) { + duk_pop(ctx); + duk_push_string(ctx, "Error"); + } else { + duk_to_string(ctx, -1); + } + + /* [ ... this name ] */ + + /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by + * accident or are they actually needed? The first ToString() + * could conceivably return 'undefined'. + */ + duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE); + if (duk_is_undefined(ctx, -1)) { + duk_pop(ctx); + duk_push_string(ctx, ""); + } else { + duk_to_string(ctx, -1); + } + + /* [ ... this name message ] */ + + if (duk_get_length(ctx, -2) == 0) { + /* name is empty -> return message */ + return 1; + } + if (duk_get_length(ctx, -1) == 0) { + /* message is empty -> return name */ + duk_pop(ctx); + return 1; + } + duk_push_string(ctx, ": "); + duk_insert(ctx, -2); /* ... name ': ' message */ + duk_concat(ctx, 3); + + return 1; +} + +#if defined(DUK_USE_TRACEBACKS) + +/* + * Traceback handling + * + * The unified helper decodes the traceback and produces various requested + * outputs. It should be optimized for size, and may leave garbage on stack, + * only the topmost return value matters. For instance, traceback separator + * and decoded strings are pushed even when looking for filename only. + * + * NOTE: although _Tracedata is an internal property, user code can currently + * write to the array (or replace it with something other than an array). + * The code below must tolerate arbitrary _Tracedata. It can throw errors + * etc, but cannot cause a segfault or memory unsafe behavior. + */ + +/* constants arbitrary, chosen for small loads */ +#define DUK__OUTPUT_TYPE_TRACEBACK (-1) +#define DUK__OUTPUT_TYPE_FILENAME 0 +#define DUK__OUTPUT_TYPE_LINENUMBER 1 + +DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t idx_td; + duk_small_int_t i; /* traceback depth fits into 16 bits */ + duk_small_int_t t; /* stack type fits into 16 bits */ + duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */ + const char *str_tailcall = " tailcall"; + const char *str_strict = " strict"; + const char *str_construct = " construct"; + const char *str_prevyield = " preventsyield"; + const char *str_directeval = " directeval"; + const char *str_empty = ""; + + DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */ + DUK_UNREF(thr); + + duk_push_this(ctx); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA); + idx_td = duk_get_top_index(ctx); + + duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE); + duk_push_this(ctx); + + /* [ ... this tracedata sep this ] */ + + /* XXX: skip null filename? */ + + if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) { + /* Current tracedata contains 2 entries per callstack entry. */ + for (i = 0; ; i += 2) { + duk_int_t pc; + duk_int_t line; + duk_int_t flags; + duk_double_t d; + const char *funcname; + const char *filename; + duk_hobject *h_func; + duk_hstring *h_name; + + duk_require_stack(ctx, 5); + duk_get_prop_index(ctx, idx_td, i); + duk_get_prop_index(ctx, idx_td, i + 1); + d = duk_to_number(ctx, -1); + pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32); + flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32); + t = (duk_small_int_t) duk_get_type(ctx, -2); + + if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) { + /* + * Ecmascript/native function call or lightfunc call + */ + + count_func++; + + /* [ ... v1(func) v2(pc+flags) ] */ + + h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */ + + duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); + duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME); + +#if defined(DUK_USE_PC2LINE) + line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc); +#else + line = 0; +#endif + + /* [ ... v1 v2 name filename ] */ + + /* When looking for .fileName/.lineNumber, blame first + * function which has a .fileName. + */ + if (duk_is_string(ctx, -1)) { + if (output_type == DUK__OUTPUT_TYPE_FILENAME) { + return 1; + } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { + duk_push_int(ctx, line); + return 1; + } + } + + /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */ + /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */ + h_name = duk_get_hstring(ctx, -2); /* may be NULL */ + funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ? + "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name); + filename = duk_get_string(ctx, -1); + filename = filename ? filename : ""; + DUK_ASSERT(funcname != NULL); + DUK_ASSERT(filename != NULL); + + if (h_func == NULL) { + duk_push_sprintf(ctx, "at %s light%s%s%s%s%s", + (const char *) funcname, + (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); + } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) { + duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s", + (const char *) funcname, + (const char *) filename, + (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); + } else { + duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s", + (const char *) funcname, + (const char *) filename, + (long) line, + (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), + (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); + } + duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */ + duk_pop_n(ctx, 3); /* -> [ ... str ] */ + } else if (t == DUK_TYPE_STRING) { + /* + * __FILE__ / __LINE__ entry, here 'pc' is line number directly. + * Sometimes __FILE__ / __LINE__ is reported as the source for + * the error (fileName, lineNumber), sometimes not. + */ + + /* [ ... v1(filename) v2(line+flags) ] */ + + /* When looking for .fileName/.lineNumber, blame compilation + * or C call site unless flagged not to do so. + */ + if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) { + if (output_type == DUK__OUTPUT_TYPE_FILENAME) { + duk_pop(ctx); + return 1; + } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { + duk_push_int(ctx, pc); + return 1; + } + } + + duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal", + (const char *) duk_get_string(ctx, -2), (long) pc); + duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */ + duk_pop(ctx); /* -> [ ... str ] */ + } else { + /* unknown, ignore */ + duk_pop_2(ctx); + break; + } + } + + if (count_func >= DUK_USE_TRACEBACK_DEPTH) { + /* Possibly truncated; there is no explicit truncation + * marker so this is the best we can do. + */ + + duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS); + } + } + + /* [ ... this tracedata sep this str1 ... strN ] */ + + if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) { + return 0; + } else { + /* The 'this' after 'sep' will get ToString() coerced by + * duk_join() automatically. We don't want to do that + * coercion when providing .fileName or .lineNumber (GH-254). + */ + duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/); + return 1; + } +} + +/* XXX: Output type could be encoded into native function 'magic' value to + * save space. For setters the stridx could be encoded into 'magic'. + */ + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) { + return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK); +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) { + return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME); +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) { + return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER); +} + +#undef DUK__OUTPUT_TYPE_TRACEBACK +#undef DUK__OUTPUT_TYPE_FILENAME +#undef DUK__OUTPUT_TYPE_LINENUMBER + +#else /* DUK_USE_TRACEBACKS */ + +/* + * Traceback handling when tracebacks disabled. + * + * The fileName / lineNumber stubs are now necessary because built-in + * data will include the accessor properties in Error.prototype. If those + * are removed for builds without tracebacks, these can also be removed. + * 'stack' should still be present and produce a ToString() equivalent: + * this is useful for user code which prints a stacktrace and expects to + * see something useful. A normal stacktrace also begins with a ToString() + * of the error so this makes sense. + */ + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) { + /* XXX: remove this native function and map 'stack' accessor + * to the toString() implementation directly. + */ + return duk_bi_error_prototype_to_string(ctx); +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) { + DUK_UNREF(ctx); + return 0; +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) { + DUK_UNREF(ctx); + return 0; +} + +#endif /* DUK_USE_TRACEBACKS */ + +DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) { + /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if + * user code called Object.defineProperty() to create an overriding + * own property. This allows user code to overwrite .fileName etc + * intuitively as e.g. "err.fileName = 'dummy'" as one might expect. + * See https://github.com/svaarala/duktape/issues/387. + */ + + DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */ + + duk_push_this(ctx); + duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key); + duk_dup(ctx, 0); + + /* [ ... obj key value ] */ + + DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T", + duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1))); + + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | + DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE | + DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/ + DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE); + return 0; +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) { + return duk__error_setter_helper(ctx, DUK_STRIDX_STACK); +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) { + return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME); +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) { + return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER); +} +/* + * Function built-ins + */ + +/* include removed: duk_internal.h */ + +DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hstring *h_sourcecode; + duk_idx_t nargs; + duk_idx_t i; + duk_small_uint_t comp_flags; + duk_hcompiledfunction *func; + duk_hobject *outer_lex_env; + duk_hobject *outer_var_env; + + /* normal and constructor calls have identical semantics */ + + nargs = duk_get_top(ctx); + for (i = 0; i < nargs; i++) { + duk_to_string(ctx, i); + } + + if (nargs == 0) { + duk_push_string(ctx, ""); + duk_push_string(ctx, ""); + } else if (nargs == 1) { + /* XXX: cover this with the generic >1 case? */ + duk_push_string(ctx, ""); + } else { + duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */ + duk_push_string(ctx, ","); + duk_insert(ctx, 1); + duk_join(ctx, nargs - 1); + } + + /* [ body formals ], formals is comma separated list that needs to be parsed */ + + DUK_ASSERT_TOP(ctx, 2); + + /* XXX: this placeholder is not always correct, but use for now. + * It will fail in corner cases; see test-dev-func-cons-args.js. + */ + duk_push_string(ctx, "function("); + duk_dup(ctx, 1); + duk_push_string(ctx, "){"); + duk_dup(ctx, 0); + duk_push_string(ctx, "}"); + duk_concat(ctx, 5); + + /* [ body formals source ] */ + + DUK_ASSERT_TOP(ctx, 3); + + /* strictness is not inherited, intentional */ + comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR; + + duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */ + h_sourcecode = duk_require_hstring(ctx, -2); + duk_js_compile(thr, + (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode), + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode), + comp_flags); + func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1); + DUK_ASSERT(func != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func)); + + /* [ body formals source template ] */ + + /* only outer_lex_env matters, as functions always get a new + * variable declaration environment. + */ + + outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; + outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; + + duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/); + + /* [ body formals source template closure ] */ + + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) { + /* ignore arguments, return undefined (E5 Section 15.3.4) */ + DUK_UNREF(ctx); + return 0; +} + +DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) { + duk_tval *tv; + + /* + * E5 Section 15.3.4.2 places few requirements on the output of + * this function: + * + * - The result is an implementation dependent representation + * of the function; in particular + * + * - The result must follow the syntax of a FunctionDeclaration. + * In particular, the function must have a name (even in the + * case of an anonymous function or a function with an empty + * name). + * + * - Note in particular that the output does NOT need to compile + * into anything useful. + */ + + + /* XXX: faster internal way to get this */ + duk_push_this(ctx); + tv = duk_get_tval(ctx, -1); + DUK_ASSERT(tv != NULL); + + if (DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv); + const char *func_name; + + /* Function name: missing/undefined is mapped to empty string, + * otherwise coerce to string. + */ + /* XXX: currently no handling for non-allowed identifier characters, + * e.g. a '{' in the function name. + */ + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); + if (duk_is_undefined(ctx, -1)) { + func_name = ""; + } else { + func_name = duk_to_string(ctx, -1); + DUK_ASSERT(func_name != NULL); + } + + /* Indicate function type in the function body using a dummy + * directive. + */ + if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) { + duk_push_sprintf(ctx, "function %s() {\"ecmascript\"}", (const char *) func_name); + } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) { + duk_push_sprintf(ctx, "function %s() {\"native\"}", (const char *) func_name); + } else if (DUK_HOBJECT_HAS_BOUND(obj)) { + duk_push_sprintf(ctx, "function %s() {\"bound\"}", (const char *) func_name); + } else { + goto type_error; + } + } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { + duk_push_lightfunc_tostring(ctx, tv); + } else { + goto type_error; + } + + return 1; + + type_error: + return DUK_RET_TYPE_ERROR; +} + +DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) { + duk_idx_t len; + duk_idx_t i; + + DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */ + + duk_push_this(ctx); + if (!duk_is_callable(ctx, -1)) { + DUK_DDD(DUK_DDDPRINT("func is not callable")); + goto type_error; + } + duk_insert(ctx, 0); + DUK_ASSERT_TOP(ctx, 3); + + DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT", + (duk_tval *) duk_get_tval(ctx, 0), + (duk_tval *) duk_get_tval(ctx, 1), + (duk_tval *) duk_get_tval(ctx, 2))); + + /* [ func thisArg argArray ] */ + + if (duk_is_null_or_undefined(ctx, 2)) { + DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args")); + len = 0; + } else if (!duk_is_object(ctx, 2)) { + goto type_error; + } else { + DUK_DDD(DUK_DDDPRINT("argArray is an object")); + + /* XXX: make this an internal helper */ + duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH); + len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */ + duk_pop(ctx); + + duk_require_stack(ctx, len); + + DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len)); + for (i = 0; i < len; i++) { + duk_get_prop_index(ctx, 2, i); + } + } + duk_remove(ctx, 2); + DUK_ASSERT_TOP(ctx, 2 + len); + + /* [ func thisArg arg1 ... argN ] */ + + DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld", + (duk_tval *) duk_get_tval(ctx, 0), + (duk_tval *) duk_get_tval(ctx, 1), + (long) len)); + duk_call_method(ctx, len); + return 1; + + type_error: + return DUK_RET_TYPE_ERROR; +} + +DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) { + duk_idx_t nargs; + + /* Step 1 is not necessary because duk_call_method() will take + * care of it. + */ + + /* vararg function, thisArg needs special handling */ + nargs = duk_get_top(ctx); /* = 1 + arg count */ + if (nargs == 0) { + duk_push_undefined(ctx); + nargs++; + } + DUK_ASSERT(nargs >= 1); + + /* [ thisArg arg1 ... argN ] */ + + duk_push_this(ctx); /* 'func' in the algorithm */ + duk_insert(ctx, 0); + + /* [ func thisArg arg1 ... argN ] */ + + DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld", + (duk_tval *) duk_get_tval(ctx, 0), + (duk_tval *) duk_get_tval(ctx, 1), + (long) (nargs - 1), + (long) duk_get_top(ctx))); + duk_call_method(ctx, nargs - 1); + return 1; +} + +/* XXX: the implementation now assumes "chained" bound functions, + * whereas "collapsed" bound functions (where there is ever only + * one bound function which directly points to a non-bound, final + * function) would require a "collapsing" implementation which + * merges argument lists etc here. + */ +DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) { + duk_hobject *h_bound; + duk_hobject *h_target; + duk_idx_t nargs; + duk_idx_t i; + + /* vararg function, careful arg handling (e.g. thisArg may not be present) */ + nargs = duk_get_top(ctx); /* = 1 + arg count */ + if (nargs == 0) { + duk_push_undefined(ctx); + nargs++; + } + DUK_ASSERT(nargs >= 1); + + duk_push_this(ctx); + if (!duk_is_callable(ctx, -1)) { + DUK_DDD(DUK_DDDPRINT("func is not callable")); + goto type_error; + } + + /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */ + DUK_ASSERT_TOP(ctx, nargs + 1); + + /* create bound function object */ + duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BOUND | + DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION), + DUK_BIDX_FUNCTION_PROTOTYPE); + h_bound = duk_get_hobject(ctx, -1); + DUK_ASSERT(h_bound != NULL); + + /* [ thisArg arg1 ... argN func boundFunc ] */ + duk_dup(ctx, -2); /* func */ + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); + + duk_dup(ctx, 0); /* thisArg */ + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); + + duk_push_array(ctx); + + /* [ thisArg arg1 ... argN func boundFunc argArray ] */ + + for (i = 0; i < nargs - 1; i++) { + duk_dup(ctx, 1 + i); + duk_put_prop_index(ctx, -2, i); + } + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE); + + /* [ thisArg arg1 ... argN func boundFunc ] */ + + /* bound function 'length' property is interesting */ + h_target = duk_get_hobject(ctx, -2); + if (h_target == NULL || /* lightfunc */ + DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) { + /* For lightfuncs, simply read the virtual property. */ + duk_int_t tmp; + duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH); + tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */ + duk_pop(ctx); + duk_push_int(ctx, (tmp < 0 ? 0 : tmp)); + } else { + duk_push_int(ctx, 0); + } + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */ + + /* caller and arguments must use the same thrower, [[ThrowTypeError]] */ + duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE); + duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE); + + /* these non-standard properties are copied for convenience */ + /* XXX: 'copy properties' API call? */ + duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC); + duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC); + + /* The 'strict' flag is copied to get the special [[Get]] of E5.1 + * Section 15.3.5.4 to apply when a 'caller' value is a strict bound + * function. Not sure if this is correct, because the specification + * is a bit ambiguous on this point but it would make sense. + */ + if (h_target == NULL) { + /* Lightfuncs are always strict. */ + DUK_HOBJECT_SET_STRICT(h_bound); + } else if (DUK_HOBJECT_HAS_STRICT(h_target)) { + DUK_HOBJECT_SET_STRICT(h_bound); + } + DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1))); + + return 1; + + type_error: + return DUK_RET_TYPE_ERROR; +} +/* + * Global object built-ins + */ + +/* include removed: duk_internal.h */ + +/* + * Encoding/decoding helpers + */ + +/* XXX: Could add fast path (for each transform callback) with direct byte + * lookups (no shifting) and no explicit check for x < 0x80 before table + * lookup. + */ + +/* Macros for creating and checking bitmasks for character encoding. + * Bit number is a bit counterintuitive, but minimizes code size. + */ +#define DUK__MKBITS(a,b,c,d,e,f,g,h) ((duk_uint8_t) ( \ + ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \ + ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \ + )) +#define DUK__CHECK_BITMASK(table,cp) ((table)[(cp) >> 3] & (1 << ((cp) & 0x07))) + +/* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */ +DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = { + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ + DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ + DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */ +}; + +/* E5.1 Section 15.1.3.4: uriUnescaped */ +DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = { + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ + DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ + DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ + DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */ +}; + +/* E5.1 Section 15.1.3.1: uriReserved + '#' */ +DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = { + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ + DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */ + DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */ +}; + +/* E5.1 Section 15.1.3.2: empty */ +DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = { + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */ +}; + +#ifdef DUK_USE_SECTION_B +/* E5.1 Section B.2.2, step 7. */ +DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = { + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ + DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ + DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ + DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */ +}; +#endif /* DUK_USE_SECTION_B */ + +#undef DUK__MKBITS + +typedef struct { + duk_hthread *thr; + duk_hstring *h_str; + duk_bufwriter_ctx bw; + const duk_uint8_t *p; + const duk_uint8_t *p_start; + const duk_uint8_t *p_end; +} duk__transform_context; + +typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp); + +/* XXX: refactor and share with other code */ +DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) { + duk_small_int_t ch; + duk_small_int_t t = 0; + + while (n > 0) { + t = t * 16; + ch = (duk_small_int_t) duk_hex_dectab[*p++]; + if (DUK_LIKELY(ch >= 0)) { + t += ch; + } else { + return -1; + } + n--; + } + return t; +} + +DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, const void *udata) { + duk_hthread *thr = (duk_hthread *) ctx; + duk__transform_context tfm_ctx_alloc; + duk__transform_context *tfm_ctx = &tfm_ctx_alloc; + duk_codepoint_t cp; + + tfm_ctx->thr = thr; + + tfm_ctx->h_str = duk_to_hstring(ctx, 0); + DUK_ASSERT(tfm_ctx->h_str != NULL); + + DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */ + + tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str); + tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str); + tfm_ctx->p = tfm_ctx->p_start; + + while (tfm_ctx->p < tfm_ctx->p_end) { + cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end); + callback(tfm_ctx, udata, cp); + } + + DUK_BW_COMPACT(thr, &tfm_ctx->bw); + + duk_to_string(ctx, -1); + return 1; +} + +DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { + duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH]; + duk_small_int_t len; + duk_codepoint_t cp1, cp2; + duk_small_int_t i, t; + const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata; + + /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes. + * Codepoint range is restricted so this is a slightly too large + * but doesn't matter. + */ + DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH); + + if (cp < 0) { + goto uri_error; + } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) { + DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp); + return; + } else if (cp >= 0xdc00L && cp <= 0xdfffL) { + goto uri_error; + } else if (cp >= 0xd800L && cp <= 0xdbffL) { + /* Needs lookahead */ + if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) { + goto uri_error; + } + if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) { + goto uri_error; + } + cp1 = cp; + cp = ((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L; + } else if (cp > 0x10ffffL) { + /* Although we can allow non-BMP characters (they'll decode + * back into surrogate pairs), we don't allow extended UTF-8 + * characters; they would encode to URIs which won't decode + * back because of strict UTF-8 checks in URI decoding. + * (However, we could just as well allow them here.) + */ + goto uri_error; + } else { + /* Non-BMP characters within valid UTF-8 range: encode as is. + * They'll decode back into surrogate pairs if the escaped + * output is decoded. + */ + ; + } + + len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf); + for (i = 0; i < len; i++) { + t = (int) xutf8_buf[i]; + DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, + &tfm_ctx->bw, + DUK_ASC_PERCENT, + (duk_uint8_t) duk_uc_nybbles[t >> 4], + (duk_uint8_t) duk_uc_nybbles[t & 0x0f]); + } + + return; + + uri_error: + DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input"); +} + +DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { + const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata; + duk_small_uint_t utf8_blen; + duk_codepoint_t min_cp; + duk_small_int_t t; /* must be signed */ + duk_small_uint_t i; + + /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH, + * percent escape path writes max two times CESU-8 encoded BMP length. + */ + DUK_BW_ENSURE(tfm_ctx->thr, + &tfm_ctx->bw, + (DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH ? + DUK_UNICODE_MAX_XUTF8_LENGTH : DUK_UNICODE_MAX_CESU8_BMP_LENGTH)); + + if (cp == (duk_codepoint_t) '%') { + const duk_uint8_t *p = tfm_ctx->p; + duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */ + + DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long) left)); + + if (left < 2) { + goto uri_error; + } + + t = duk__decode_hex_escape(p, 2); + DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long) t)); + if (t < 0) { + goto uri_error; + } + + if (t < 0x80) { + if (DUK__CHECK_BITMASK(reserved_table, t)) { + /* decode '%xx' to '%xx' if decoded char in reserved set */ + DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start); + DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, + &tfm_ctx->bw, + DUK_ASC_PERCENT, + p[0], + p[1]); + } else { + DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) t); + } + tfm_ctx->p += 2; + return; + } + + /* Decode UTF-8 codepoint from a sequence of hex escapes. The + * first byte of the sequence has been decoded to 't'. + * + * Note that UTF-8 validation must be strict according to the + * specification: E5.1 Section 15.1.3, decode algorithm step + * 4.d.vii.8. URIError from non-shortest encodings is also + * specifically noted in the spec. + */ + + DUK_ASSERT(t >= 0x80); + if (t < 0xc0) { + /* continuation byte */ + goto uri_error; + } else if (t < 0xe0) { + /* 110x xxxx; 2 bytes */ + utf8_blen = 2; + min_cp = 0x80L; + cp = t & 0x1f; + } else if (t < 0xf0) { + /* 1110 xxxx; 3 bytes */ + utf8_blen = 3; + min_cp = 0x800L; + cp = t & 0x0f; + } else if (t < 0xf8) { + /* 1111 0xxx; 4 bytes */ + utf8_blen = 4; + min_cp = 0x10000L; + cp = t & 0x07; + } else { + /* extended utf-8 not allowed for URIs */ + goto uri_error; + } + + if (left < utf8_blen * 3 - 1) { + /* '%xx%xx...%xx', p points to char after first '%' */ + goto uri_error; + } + + p += 3; + for (i = 1; i < utf8_blen; i++) { + /* p points to digit part ('%xy', p points to 'x') */ + t = duk__decode_hex_escape(p, 2); + DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx", + (long) i, (long) utf8_blen, (long) cp, (unsigned long) t)); + if (t < 0) { + goto uri_error; + } + if ((t & 0xc0) != 0x80) { + goto uri_error; + } + cp = (cp << 6) + (t & 0x3f); + p += 3; + } + p--; /* p overshoots */ + tfm_ctx->p = p; + + DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long) cp, (long) min_cp)); + + if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) { + goto uri_error; + } + + /* The E5.1 algorithm checks whether or not a decoded codepoint + * is below 0x80 and perhaps may be in the "reserved" set. + * This seems pointless because the single byte UTF-8 case is + * handled separately, and non-shortest encodings are rejected. + * So, 'cp' cannot be below 0x80 here, and thus cannot be in + * the reserved set. + */ + + /* utf-8 validation ensures these */ + DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL); + + if (cp >= 0x10000L) { + cp -= 0x10000L; + DUK_ASSERT(cp < 0x100000L); + + DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L)); + DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffUL) + 0xdc00L)); + } else { + DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp); + } + } else { + DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp); + } + return; + + uri_error: + DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input"); +} + +#ifdef DUK_USE_SECTION_B +DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { + DUK_UNREF(udata); + + DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6); + + if (cp < 0) { + goto esc_error; + } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) { + DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp); + } else if (cp < 0x100L) { + DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, + &tfm_ctx->bw, + (duk_uint8_t) DUK_ASC_PERCENT, + (duk_uint8_t) duk_uc_nybbles[cp >> 4], + (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]); + } else if (cp < 0x10000L) { + DUK_BW_WRITE_RAW_U8_6(tfm_ctx->thr, + &tfm_ctx->bw, + (duk_uint8_t) DUK_ASC_PERCENT, + (duk_uint8_t) DUK_ASC_LC_U, + (duk_uint8_t) duk_uc_nybbles[cp >> 12], + (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f], + (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f], + (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]); + } else { + /* Characters outside BMP cannot be escape()'d. We could + * encode them as surrogate pairs (for codepoints inside + * valid UTF-8 range, but not extended UTF-8). Because + * escape() and unescape() are legacy functions, we don't. + */ + goto esc_error; + } + + return; + + esc_error: + DUK_ERROR_TYPE(tfm_ctx->thr, "invalid input"); +} + +DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { + duk_small_int_t t; + + DUK_UNREF(udata); + + if (cp == (duk_codepoint_t) '%') { + const duk_uint8_t *p = tfm_ctx->p; + duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */ + + if (left >= 5 && p[0] == 'u' && + ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) { + cp = (duk_codepoint_t) t; + tfm_ctx->p += 5; + } else if (left >= 2 && + ((t = duk__decode_hex_escape(p, 2)) >= 0)) { + cp = (duk_codepoint_t) t; + tfm_ctx->p += 2; + } + } + + DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp); +} +#endif /* DUK_USE_SECTION_B */ + +/* + * Eval + * + * Eval needs to handle both a "direct eval" and an "indirect eval". + * Direct eval handling needs access to the caller's activation so that its + * lexical environment can be accessed. A direct eval is only possible from + * Ecmascript code; an indirect eval call is possible also from C code. + * When an indirect eval call is made from C code, there may not be a + * calling activation at all which needs careful handling. + */ + +DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hstring *h; + duk_activation *act_caller; + duk_activation *act_eval; + duk_activation *act; + duk_hcompiledfunction *func; + duk_hobject *outer_lex_env; + duk_hobject *outer_var_env; + duk_bool_t this_to_global = 1; + duk_small_uint_t comp_flags; + duk_int_t level = -2; + + DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */ + DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */ + DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */ + (thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */ + + /* + * callstack_top - 1 --> this function + * callstack_top - 2 --> caller (may not exist) + * + * If called directly from C, callstack_top might be 1. If calling + * activation doesn't exist, call must be indirect. + */ + + h = duk_get_hstring(ctx, 0); + if (!h) { + return 1; /* return arg as-is */ + } + +#if defined(DUK_USE_DEBUGGER_SUPPORT) + /* NOTE: level is used only by the debugger and should never be present + * for an Ecmascript eval(). + */ + DUK_ASSERT(level == -2); /* by default, use caller's environment */ + if (duk_get_top(ctx) >= 2 && duk_is_number(ctx, 1)) { + level = duk_get_int(ctx, 1); + } + DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */ +#endif + + /* [ source ] */ + + comp_flags = DUK_JS_COMPILE_FLAG_EVAL; + act_eval = thr->callstack + thr->callstack_top - 1; /* this function */ + if (thr->callstack_top >= (duk_size_t) -level) { + /* Have a calling activation, check for direct eval (otherwise + * assume indirect eval. + */ + act_caller = thr->callstack + thr->callstack_top + level; /* caller */ + if ((act_caller->flags & DUK_ACT_FLAG_STRICT) && + (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) { + /* Only direct eval inherits strictness from calling code + * (E5.1 Section 10.1.1). + */ + comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + } + } else { + DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0); + } + act_caller = NULL; /* avoid dereference after potential callstack realloc */ + act_eval = NULL; + + duk_push_hstring_stridx(ctx, DUK_STRIDX_INPUT); /* XXX: copy from caller? */ + duk_js_compile(thr, + (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h), + comp_flags); + func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1); + DUK_ASSERT(func != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func)); + + /* [ source template ] */ + + /* E5 Section 10.4.2 */ + DUK_ASSERT(thr->callstack_top >= 1); + act = thr->callstack + thr->callstack_top - 1; /* this function */ + if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { + DUK_ASSERT(thr->callstack_top >= 2); + act = thr->callstack + thr->callstack_top + level; /* caller */ + if (act->lex_env == NULL) { + DUK_ASSERT(act->var_env == NULL); + DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); + + /* this may have side effects, so re-lookup act */ + duk_js_init_activation_environment_records_delayed(thr, act); + act = thr->callstack + thr->callstack_top + level; + } + DUK_ASSERT(act->lex_env != NULL); + DUK_ASSERT(act->var_env != NULL); + + this_to_global = 0; + + if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) { + duk_hobject *new_env; + duk_hobject *act_lex_env; + + DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> " + "var_env and lex_env to a fresh env, " + "this_binding to caller's this_binding")); + + act = thr->callstack + thr->callstack_top + level; /* caller */ + act_lex_env = act->lex_env; + act = NULL; /* invalidated */ + + (void) duk_push_object_helper_proto(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), + act_lex_env); + new_env = duk_require_hobject(ctx, -1); + DUK_ASSERT(new_env != NULL); + DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", + (duk_heaphdr *) new_env)); + + outer_lex_env = new_env; + outer_var_env = new_env; + + duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */ + + /* compiler's responsibility */ + DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func)); + } else { + DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> " + "var_env and lex_env to caller's envs, " + "this_binding to caller's this_binding")); + + outer_lex_env = act->lex_env; + outer_var_env = act->var_env; + + /* compiler's responsibility */ + DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func)); + } + } else { + DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to " + "global object, this_binding to global object")); + + this_to_global = 1; + outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; + outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; + } + act = NULL; + + /* Eval code doesn't need an automatic .prototype object. */ + duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/); + + /* [ source template closure ] */ + + if (this_to_global) { + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); + duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL); + } else { + duk_tval *tv; + DUK_ASSERT(thr->callstack_top >= 2); + act = thr->callstack + thr->callstack_top + level; /* caller */ + tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */ + DUK_ASSERT(tv >= thr->valstack); + duk_push_tval(ctx, tv); + } + + DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T", + (duk_heaphdr *) outer_lex_env, + (duk_heaphdr *) outer_var_env, + duk_get_tval(ctx, -1))); + + /* [ source template closure this ] */ + + duk_call_method(ctx, 0); + + /* [ source template result ] */ + + return 1; +} + +/* + * Parsing of ints and floats + */ + +DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) { + duk_int32_t radix; + duk_small_uint_t s2n_flags; + + DUK_ASSERT_TOP(ctx, 2); + duk_to_string(ctx, 0); + + radix = duk_to_int32(ctx, 1); + + s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | + DUK_S2N_FLAG_ALLOW_GARBAGE | + DUK_S2N_FLAG_ALLOW_PLUS | + DUK_S2N_FLAG_ALLOW_MINUS | + DUK_S2N_FLAG_ALLOW_LEADING_ZERO | + DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT; + + /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT. + * + * Don't autodetect octals (from leading zeroes), require user code to + * provide an explicit radix 8 for parsing octal. See write-up from Mozilla: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation + */ + + if (radix != 0) { + if (radix < 2 || radix > 36) { + goto ret_nan; + } + if (radix != 16) { + s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT; + } + } else { + radix = 10; + } + + duk_dup(ctx, 0); + duk_numconv_parse(ctx, radix, s2n_flags); + return 1; + + ret_nan: + duk_push_nan(ctx); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) { + duk_small_uint_t s2n_flags; + duk_int32_t radix; + + DUK_ASSERT_TOP(ctx, 1); + duk_to_string(ctx, 0); + + radix = 10; + + /* XXX: check flags */ + s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | + DUK_S2N_FLAG_ALLOW_EXP | + DUK_S2N_FLAG_ALLOW_GARBAGE | + DUK_S2N_FLAG_ALLOW_PLUS | + DUK_S2N_FLAG_ALLOW_MINUS | + DUK_S2N_FLAG_ALLOW_INF | + DUK_S2N_FLAG_ALLOW_FRAC | + DUK_S2N_FLAG_ALLOW_NAKED_FRAC | + DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | + DUK_S2N_FLAG_ALLOW_LEADING_ZERO; + + duk_numconv_parse(ctx, radix, s2n_flags); + return 1; +} + +/* + * Number checkers + */ + +DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx) { + duk_double_t d = duk_to_number(ctx, 0); + duk_push_boolean(ctx, DUK_ISNAN(d)); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) { + duk_double_t d = duk_to_number(ctx, 0); + duk_push_boolean(ctx, DUK_ISFINITE(d)); + return 1; +} + +/* + * URI handling + */ + +DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) { + return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table); +} + +DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx) { + return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table); +} + +DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx) { + return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table); +} + +DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx) { + return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table); +} + +#ifdef DUK_USE_SECTION_B +DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) { + return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL); +} + +DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) { + return duk__transform_helper(ctx, duk__transform_callback_unescape, (const void *) NULL); +} +#else /* DUK_USE_SECTION_B */ +DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} + +DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_SECTION_B */ + +#if defined(DUK_USE_BROWSER_LIKE) && (defined(DUK_USE_FILE_IO) || defined(DUK_USE_DEBUGGER_SUPPORT)) +DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_int_t magic; + duk_idx_t nargs; + const duk_uint8_t *buf; + duk_size_t sz_buf; + const char nl = (const char) DUK_ASC_LF; +#ifndef DUK_USE_PREFER_SIZE + duk_uint8_t buf_stack[256]; +#endif +#ifdef DUK_USE_FILE_IO + duk_file *f_out; +#endif + + DUK_UNREF(thr); + + magic = duk_get_current_magic(ctx); + DUK_UNREF(magic); + + nargs = duk_get_top(ctx); + + /* If argument count is 1 and first argument is a buffer, write the buffer + * as raw data into the file without a newline; this allows exact control + * over stdout/stderr without an additional entrypoint (useful for now). + * + * Otherwise current print/alert semantics are to ToString() coerce + * arguments, join them with a single space, and append a newline. + */ + + if (nargs == 1 && duk_is_buffer(ctx, 0)) { + buf = (const duk_uint8_t *) duk_get_buffer(ctx, 0, &sz_buf); + DUK_ASSERT(buf != NULL); + } else if (nargs > 0) { +#ifdef DUK_USE_PREFER_SIZE + /* Compact but lots of churn. */ + duk_push_hstring_stridx(thr, DUK_STRIDX_SPACE); + duk_insert(ctx, 0); + duk_join(ctx, nargs); + duk_push_string(thr, "\n"); + duk_concat(ctx, 2); + buf = (const duk_uint8_t *) duk_get_lstring(ctx, -1, &sz_buf); + DUK_ASSERT(buf != NULL); +#else /* DUK_USE_PREFER_SIZE */ + /* Higher footprint, less churn. */ + duk_idx_t i; + duk_size_t sz_str; + const duk_uint8_t *p_str; + duk_uint8_t *p; + + sz_buf = (duk_size_t) nargs; /* spaces (nargs - 1) + newline */ + for (i = 0; i < nargs; i++) { + (void) duk_to_lstring(ctx, i, &sz_str); + sz_buf += sz_str; + } + + if (sz_buf <= sizeof(buf_stack)) { + p = (duk_uint8_t *) buf_stack; + } else { + p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf); + DUK_ASSERT(p != NULL); + } + + buf = (const duk_uint8_t *) p; + for (i = 0; i < nargs; i++) { + p_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &sz_str); + DUK_ASSERT(p_str != NULL); + DUK_MEMCPY((void *) p, (const void *) p_str, sz_str); + p += sz_str; + *p++ = (duk_uint8_t) (i == nargs - 1 ? DUK_ASC_LF : DUK_ASC_SPACE); + } + DUK_ASSERT((const duk_uint8_t *) p == buf + sz_buf); +#endif /* DUK_USE_PREFER_SIZE */ + } else { + buf = (const duk_uint8_t *) &nl; + sz_buf = 1; + } + + /* 'buf' contains the string to write, 'sz_buf' contains the length + * (which may be zero). + */ + DUK_ASSERT(buf != NULL); + + if (sz_buf == 0) { + return 0; + } + +#ifdef DUK_USE_FILE_IO + f_out = (magic ? DUK_STDERR : DUK_STDOUT); + DUK_FWRITE((const void *) buf, 1, (size_t) sz_buf, f_out); + DUK_FFLUSH(f_out); +#endif + +#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_PRINTALERT) + if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + duk_debug_write_notify(thr, magic ? DUK_DBG_CMD_ALERT : DUK_DBG_CMD_PRINT); + duk_debug_write_string(thr, (const char *) buf, sz_buf); + duk_debug_write_eom(thr); + } +#endif + return 0; +} +#elif defined(DUK_USE_BROWSER_LIKE) /* print provider */ +DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) { + DUK_UNREF(ctx); + return 0; +} +#else /* print provider */ +DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* print provider */ + +/* + * CommonJS require() and modules support + */ + +#if defined(DUK_USE_COMMONJS_MODULES) +DUK_LOCAL void duk__bi_global_resolve_module_id(duk_context *ctx, const char *req_id, const char *mod_id) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_uint8_t buf[DUK_BI_COMMONJS_MODULE_ID_LIMIT]; + duk_uint8_t *p; + duk_uint8_t *q; + duk_uint8_t *q_last; /* last component */ + duk_int_t int_rc; + + DUK_ASSERT(req_id != NULL); + /* mod_id may be NULL */ + + /* + * A few notes on the algorithm: + * + * - Terms are not allowed to begin with a period unless the term + * is either '.' or '..'. This simplifies implementation (and + * is within CommonJS modules specification). + * + * - There are few output bound checks here. This is on purpose: + * the resolution input is length checked and the output is never + * longer than the input. The resolved output is written directly + * over the input because it's never longer than the input at any + * point in the algorithm. + * + * - Non-ASCII characters are processed as individual bytes and + * need no special treatment. However, U+0000 terminates the + * algorithm; this is not an issue because U+0000 is not a + * desirable term character anyway. + */ + + /* + * Set up the resolution input which is the requested ID directly + * (if absolute or no current module path) or with current module + * ID prepended (if relative and current module path exists). + * + * Suppose current module is 'foo/bar' and relative path is './quux'. + * The 'bar' component must be replaced so the initial input here is + * 'foo/bar/.././quux'. + */ + + if (mod_id != NULL && req_id[0] == '.') { + int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s/../%s", mod_id, req_id); + } else { + int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s", req_id); + } + if (int_rc >= (duk_int_t) sizeof(buf) || int_rc < 0) { + /* Potentially truncated, NUL not guaranteed in any case. + * The (int_rc < 0) case should not occur in practice. + */ + DUK_DD(DUK_DDPRINT("resolve error: temporary working module ID doesn't fit into resolve buffer")); + goto resolve_error; + } + DUK_ASSERT(DUK_STRLEN((const char *) buf) < sizeof(buf)); /* at most sizeof(buf) - 1 */ + + DUK_DDD(DUK_DDDPRINT("input module id: '%s'", (const char *) buf)); + + /* + * Resolution loop. At the top of the loop we're expecting a valid + * term: '.', '..', or a non-empty identifier not starting with a period. + */ + + p = buf; + q = buf; + for (;;) { + duk_uint_fast8_t c; + + /* Here 'p' always points to the start of a term. + * + * We can also unconditionally reset q_last here: if this is + * the last (non-empty) term q_last will have the right value + * on loop exit. + */ + + DUK_ASSERT(p >= q); /* output is never longer than input during resolution */ + + DUK_DDD(DUK_DDDPRINT("resolve loop top: p -> '%s', q=%p, buf=%p", + (const char *) p, (void *) q, (void *) buf)); + + q_last = q; + + c = *p++; + if (DUK_UNLIKELY(c == 0)) { + DUK_DD(DUK_DDPRINT("resolve error: requested ID must end with a non-empty term")); + goto resolve_error; + } else if (DUK_UNLIKELY(c == '.')) { + c = *p++; + if (c == '/') { + /* Term was '.' and is eaten entirely (including dup slashes). */ + goto eat_dup_slashes; + } + if (c == '.' && *p == '/') { + /* Term was '..', backtrack resolved name by one component. + * q[-1] = previous slash (or beyond start of buffer) + * q[-2] = last char of previous component (or beyond start of buffer) + */ + p++; /* eat (first) input slash */ + DUK_ASSERT(q >= buf); + if (q == buf) { + DUK_DD(DUK_DDPRINT("resolve error: term was '..' but nothing to backtrack")); + goto resolve_error; + } + DUK_ASSERT(*(q - 1) == '/'); + q--; /* backtrack to last output slash (dups already eliminated) */ + for (;;) { + /* Backtrack to previous slash or start of buffer. */ + DUK_ASSERT(q >= buf); + if (q == buf) { + break; + } + if (*(q - 1) == '/') { + break; + } + q--; + } + goto eat_dup_slashes; + } + DUK_DD(DUK_DDPRINT("resolve error: term begins with '.' but is not '.' or '..' (not allowed now)")); + goto resolve_error; + } else if (DUK_UNLIKELY(c == '/')) { + /* e.g. require('/foo'), empty terms not allowed */ + DUK_DD(DUK_DDPRINT("resolve error: empty term (not allowed now)")); + goto resolve_error; + } else { + for (;;) { + /* Copy term name until end or '/'. */ + *q++ = c; + c = *p++; + if (DUK_UNLIKELY(c == 0)) { + /* This was the last term, and q_last was + * updated to match this term at loop top. + */ + goto loop_done; + } else if (DUK_UNLIKELY(c == '/')) { + *q++ = '/'; + break; + } else { + /* write on next loop */ + } + } + } + + eat_dup_slashes: + for (;;) { + /* eat dup slashes */ + c = *p; + if (DUK_LIKELY(c != '/')) { + break; + } + p++; + } + } + loop_done: + /* Output #1: resolved absolute name */ + DUK_ASSERT(q >= buf); + duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf)); + + /* Output #2: last component name */ + DUK_ASSERT(q >= q_last); + DUK_ASSERT(q_last >= buf); + duk_push_lstring(ctx, (const char *) q_last, (size_t) (q - q_last)); + + DUK_DD(DUK_DDPRINT("after resolving module name: buf=%p, q_last=%p, q=%p", + (void *) buf, (void *) q_last, (void *) q)); + return; + + resolve_error: + DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "cannot resolve module id: %s", (const char *) req_id); +} +#endif /* DUK_USE_COMMONJS_MODULES */ + +#if defined(DUK_USE_COMMONJS_MODULES) +/* Stack indices for better readability */ +#define DUK__IDX_REQUESTED_ID 0 /* Module id requested */ +#define DUK__IDX_REQUIRE 1 /* Current require() function */ +#define DUK__IDX_REQUIRE_ID 2 /* The base ID of the current require() function, resolution base */ +#define DUK__IDX_RESOLVED_ID 3 /* Resolved, normalized absolute module ID */ +#define DUK__IDX_LASTCOMP 4 /* Last component name in resolved path */ +#define DUK__IDX_DUKTAPE 5 /* Duktape object */ +#define DUK__IDX_MODLOADED 6 /* Duktape.modLoaded[] module cache */ +#define DUK__IDX_UNDEFINED 7 /* 'undefined', artifact of lookup */ +#define DUK__IDX_FRESH_REQUIRE 8 /* New require() function for module, updated resolution base */ +#define DUK__IDX_EXPORTS 9 /* Default exports table */ +#define DUK__IDX_MODULE 10 /* Module object containing module.exports, etc */ + +DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) { + const char *str_req_id; /* requested identifier */ + const char *str_mod_id; /* require.id of current module */ + duk_int_t pcall_rc; + + /* NOTE: we try to minimize code size by avoiding unnecessary pops, + * so the stack looks a bit cluttered in this function. DUK_ASSERT_TOP() + * assertions are used to ensure stack configuration is correct at each + * step. + */ + + /* + * Resolve module identifier into canonical absolute form. + */ + + str_req_id = duk_require_string(ctx, DUK__IDX_REQUESTED_ID); + duk_push_current_function(ctx); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ID); + str_mod_id = duk_get_string(ctx, DUK__IDX_REQUIRE_ID); /* ignore non-strings */ + DUK_DDD(DUK_DDDPRINT("resolve module id: requested=%!T, currentmodule=%!T", + duk_get_tval(ctx, DUK__IDX_REQUESTED_ID), + duk_get_tval(ctx, DUK__IDX_REQUIRE_ID))); + duk__bi_global_resolve_module_id(ctx, str_req_id, str_mod_id); + str_req_id = NULL; + str_mod_id = NULL; + DUK_DDD(DUK_DDDPRINT("resolved module id: requested=%!T, currentmodule=%!T, result=%!T, lastcomp=%!T", + duk_get_tval(ctx, DUK__IDX_REQUESTED_ID), + duk_get_tval(ctx, DUK__IDX_REQUIRE_ID), + duk_get_tval(ctx, DUK__IDX_RESOLVED_ID), + duk_get_tval(ctx, DUK__IDX_LASTCOMP))); + + /* [ requested_id require require.id resolved_id last_comp ] */ + DUK_ASSERT_TOP(ctx, DUK__IDX_LASTCOMP + 1); + + /* + * Cached module check. + * + * If module has been loaded or its loading has already begun without + * finishing, return the same cached value ('exports'). The value is + * registered when module load starts so that circular references can + * be supported to some extent. + */ + + duk_push_hobject_bidx(ctx, DUK_BIDX_DUKTAPE); + duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_LOADED); /* Duktape.modLoaded */ + (void) duk_require_hobject(ctx, DUK__IDX_MODLOADED); + DUK_ASSERT_TOP(ctx, DUK__IDX_MODLOADED + 1); + + duk_dup(ctx, DUK__IDX_RESOLVED_ID); + if (duk_get_prop(ctx, DUK__IDX_MODLOADED)) { + /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded Duktape.modLoaded[id] ] */ + DUK_DD(DUK_DDPRINT("module already loaded: %!T", + duk_get_tval(ctx, DUK__IDX_RESOLVED_ID))); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_EXPORTS); /* return module.exports */ + return 1; + } + DUK_ASSERT_TOP(ctx, DUK__IDX_UNDEFINED + 1); + + /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined ] */ + + /* + * Module not loaded (and loading not started previously). + * + * Create a new require() function with 'id' set to resolved ID + * of module being loaded. Also create 'exports' and 'module' + * tables but don't register exports to the loaded table yet. + * We don't want to do that unless the user module search callbacks + * succeeds in finding the module. + */ + + DUK_D(DUK_DPRINT("loading module %!T, resolution base %!T, requested ID %!T -> resolved ID %!T, last component %!T", + duk_get_tval(ctx, DUK__IDX_RESOLVED_ID), + duk_get_tval(ctx, DUK__IDX_REQUIRE_ID), + duk_get_tval(ctx, DUK__IDX_REQUESTED_ID), + duk_get_tval(ctx, DUK__IDX_RESOLVED_ID), + duk_get_tval(ctx, DUK__IDX_LASTCOMP))); + + /* Fresh require: require.id is left configurable (but not writable) + * so that is not easy to accidentally tweak it, but it can still be + * done with Object.defineProperty(). + * + * XXX: require.id could also be just made non-configurable, as there + * is no practical reason to touch it. + */ + duk_push_c_function(ctx, duk_bi_global_object_require, 1 /*nargs*/); + duk_push_hstring_stridx(ctx, DUK_STRIDX_REQUIRE); + duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); + duk_dup(ctx, DUK__IDX_RESOLVED_ID); + duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_C); /* a fresh require() with require.id = resolved target module id */ + + /* Module table: + * - module.exports: initial exports table (may be replaced by user) + * - module.id is non-writable and non-configurable, as the CommonJS + * spec suggests this if possible + * - module.filename: not set, defaults to resolved ID if not explicitly + * set by modSearch() (note capitalization, not .fileName, matches Node.js) + * - module.name: not set, defaults to last component of resolved ID if + * not explicitly set by modSearch() + */ + duk_push_object(ctx); /* exports */ + duk_push_object(ctx); /* module */ + duk_dup(ctx, DUK__IDX_EXPORTS); + duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS, DUK_PROPDESC_FLAGS_WC); /* module.exports = exports */ + duk_dup(ctx, DUK__IDX_RESOLVED_ID); /* resolved id: require(id) must return this same module */ + duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_NONE); /* module.id = resolved_id */ + duk_compact(ctx, DUK__IDX_MODULE); /* module table remains registered to modLoaded, minimize its size */ + DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 1); + + DUK_DD(DUK_DDPRINT("module table created: %!T", duk_get_tval(ctx, DUK__IDX_MODULE))); + + /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module ] */ + + /* Register the module table early to modLoaded[] so that we can + * support circular references even in modSearch(). If an error + * is thrown, we'll delete the reference. + */ + duk_dup(ctx, DUK__IDX_RESOLVED_ID); + duk_dup(ctx, DUK__IDX_MODULE); + duk_put_prop(ctx, DUK__IDX_MODLOADED); /* Duktape.modLoaded[resolved_id] = module */ + + /* + * Call user provided module search function and build the wrapped + * module source code (if necessary). The module search function + * can be used to implement pure Ecmacsript, pure C, and mixed + * Ecmascript/C modules. + * + * The module search function can operate on the exports table directly + * (e.g. DLL code can register values to it). It can also return a + * string which is interpreted as module source code (if a non-string + * is returned the module is assumed to be a pure C one). If a module + * cannot be found, an error must be thrown by the user callback. + * + * Because Duktape.modLoaded[] already contains the module being + * loaded, circular references for C modules should also work + * (although expected to be quite rare). + */ + + duk_push_string(ctx, "(function(require,exports,module){"); + + /* Duktape.modSearch(resolved_id, fresh_require, exports, module). */ + duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_SEARCH); /* Duktape.modSearch */ + duk_dup(ctx, DUK__IDX_RESOLVED_ID); + duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); + duk_dup(ctx, DUK__IDX_EXPORTS); + duk_dup(ctx, DUK__IDX_MODULE); /* [ ... Duktape.modSearch resolved_id last_comp fresh_require exports module ] */ + pcall_rc = duk_pcall(ctx, 4 /*nargs*/); /* -> [ ... source ] */ + DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 3); + + if (pcall_rc != DUK_EXEC_SUCCESS) { + /* Delete entry in Duktape.modLoaded[] and rethrow. */ + goto delete_rethrow; + } + + /* If user callback did not return source code, module loading + * is finished (user callback initialized exports table directly). + */ + if (!duk_is_string(ctx, -1)) { + /* User callback did not return source code, so module loading + * is finished: just update modLoaded with final module.exports + * and we're done. + */ + goto return_exports; + } + + /* Finish the wrapped module source. Force module.filename as the + * function .fileName so it gets set for functions defined within a + * module. This also ensures loggers created within the module get + * the module ID (or overridden filename) as their default logger name. + * (Note capitalization: .filename matches Node.js while .fileName is + * used elsewhere in Duktape.) + */ + duk_push_string(ctx, "})"); + duk_concat(ctx, 3); + if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_FILENAME)) { + /* module.filename for .fileName, default to resolved ID if + * not present. + */ + duk_pop(ctx); + duk_dup(ctx, DUK__IDX_RESOLVED_ID); + } + duk_eval_raw(ctx, NULL, 0, DUK_COMPILE_EVAL); + + /* Module has now evaluated to a wrapped module function. Force its + * .name to match module.name (defaults to last component of resolved + * ID) so that it is shown in stack traces too. Note that we must not + * introduce an actual name binding into the function scope (which is + * usually the case with a named function) because it would affect the + * scope seen by the module and shadow accesses to globals of the same name. + * This is now done by compiling the function as anonymous and then forcing + * its .name without setting a "has name binding" flag. + */ + + duk_push_hstring_stridx(ctx, DUK_STRIDX_NAME); + if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_NAME)) { + /* module.name for .name, default to last component if + * not present. + */ + duk_pop(ctx); + duk_dup(ctx, DUK__IDX_LASTCOMP); + } + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE); + + /* + * Call the wrapped module function. + * + * Use a protected call so that we can update Duktape.modLoaded[resolved_id] + * even if the module throws an error. + */ + + /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func ] */ + DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2); + + duk_dup(ctx, DUK__IDX_EXPORTS); /* exports (this binding) */ + duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); /* fresh require (argument) */ + duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS); /* relookup exports from module.exports in case it was changed by modSearch */ + duk_dup(ctx, DUK__IDX_MODULE); /* module (argument) */ + DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 6); + + /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func exports fresh_require exports module ] */ + + pcall_rc = duk_pcall_method(ctx, 3 /*nargs*/); + if (pcall_rc != DUK_EXEC_SUCCESS) { + /* Module loading failed. Node.js will forget the module + * registration so that another require() will try to load + * the module again. Mimic that behavior. + */ + goto delete_rethrow; + } + + /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module result(ignored) ] */ + DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2); + + /* fall through */ + + return_exports: + duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS); + duk_compact(ctx, -1); /* compact the exports table */ + return 1; /* return module.exports */ + + delete_rethrow: + duk_dup(ctx, DUK__IDX_RESOLVED_ID); + duk_del_prop(ctx, DUK__IDX_MODLOADED); /* delete Duktape.modLoaded[resolved_id] */ + duk_throw(ctx); /* rethrow original error */ + return 0; /* not reachable */ +} + +#undef DUK__IDX_REQUESTED_ID +#undef DUK__IDX_REQUIRE +#undef DUK__IDX_REQUIRE_ID +#undef DUK__IDX_RESOLVED_ID +#undef DUK__IDX_LASTCOMP +#undef DUK__IDX_DUKTAPE +#undef DUK__IDX_MODLOADED +#undef DUK__IDX_UNDEFINED +#undef DUK__IDX_FRESH_REQUIRE +#undef DUK__IDX_EXPORTS +#undef DUK__IDX_MODULE +#else +DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNSUPPORTED_ERROR; +} +#endif /* DUK_USE_COMMONJS_MODULES */ +/* + * JSON built-ins. + * + * See doc/json.rst. + * + * Codepoints are handled as duk_uint_fast32_t to ensure that the full + * unsigned 32-bit range is supported. This matters to e.g. JX. + * + * Input parsing doesn't do an explicit end-of-input check at all. This is + * safe: input string data is always NUL-terminated (0x00) and valid JSON + * inputs never contain plain NUL characters, so that as long as syntax checks + * are correct, we'll never read past the NUL. This approach reduces code size + * and improves parsing performance, but it's critical that syntax checks are + * indeed correct! + */ + +/* include removed: duk_internal.h */ + +/* + * Local defines and forward declarations. + */ + +#define DUK__JSON_DECSTR_BUFSIZE 128 +#define DUK__JSON_DECSTR_CHUNKSIZE 64 +#define DUK__JSON_ENCSTR_CHUNKSIZE 64 +#define DUK__JSON_STRINGIFY_BUFSIZE 128 +#define DUK__JSON_MAX_ESC_LEN 10 /* '\Udeadbeef' */ + +DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n); +DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx); +DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx); +#ifdef DUK_USE_JX +DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx); +#endif +DUK_LOCAL_DECL void duk__dec_number(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL void duk__dec_object(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL void duk__dec_array(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL void duk__dec_value(duk_json_dec_ctx *js_ctx); +DUK_LOCAL_DECL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx); + +DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch); +DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2); +DUK_LOCAL_DECL void duk__unemit_1(duk_json_enc_ctx *js_ctx); +DUK_LOCAL_DECL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h); +#if defined(DUK_USE_FASTINT) +DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p); +#endif +DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx); +DUK_LOCAL_DECL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q); +DUK_LOCAL_DECL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k); +DUK_LOCAL_DECL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str); +DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top); +DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top); +DUK_LOCAL_DECL void duk__enc_object(duk_json_enc_ctx *js_ctx); +DUK_LOCAL_DECL void duk__enc_array(duk_json_enc_ctx *js_ctx); +DUK_LOCAL_DECL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder); +DUK_LOCAL_DECL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv); +DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx); +#if defined(DUK_USE_FASTINT) +DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv); +#endif +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) +DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr); +DUK_LOCAL_DECL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj); +#endif +DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth); + +/* + * Helper tables + */ + +#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH) +DUK_LOCAL const duk_uint8_t duk__json_quotestr_lookup[256] = { + /* 0x00 ... 0x7f: as is + * 0x80: escape generically + * 0x81: slow path + * 0xa0 ... 0xff: backslash + one char + */ + + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe2, 0xf4, 0xee, 0x80, 0xe6, 0xf2, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x20, 0x21, 0xa2, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0xdc, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81 +}; +#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ +DUK_LOCAL const duk_uint8_t duk__json_quotestr_esc[14] = { + DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, + DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, + DUK_ASC_LC_B, DUK_ASC_LC_T, DUK_ASC_LC_N, DUK_ASC_NUL, + DUK_ASC_LC_F, DUK_ASC_LC_R +}; +#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ + +#if defined(DUK_USE_JSON_DECSTRING_FASTPATH) +DUK_LOCAL const duk_uint8_t duk__json_decstr_lookup[256] = { + /* 0x00: slow path + * other: as is + */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x00, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; +#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */ + +#if defined(DUK_USE_JSON_EATWHITE_FASTPATH) +DUK_LOCAL const duk_uint8_t duk__json_eatwhite_lookup[256] = { + /* 0x00: finish (non-white) + * 0x01: continue + */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */ + +#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH) +DUK_LOCAL const duk_uint8_t duk__json_decnumber_lookup[256] = { + /* 0x00: finish (not part of number) + * 0x01: continue + */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */ + +/* + * Parsing implementation. + * + * JSON lexer is now separate from duk_lexer.c because there are numerous + * small differences making it difficult to share the lexer. + * + * The parser here works with raw bytes directly; this works because all + * JSON delimiters are ASCII characters. Invalid xUTF-8 encoded values + * inside strings will be passed on without normalization; this is not a + * compliance concern because compliant inputs will always be valid + * CESU-8 encodings. + */ + +DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) { + /* Shared handler to minimize parser size. Cause will be + * hidden, unfortunately, but we'll have an offset which + * is often quite enough. + */ + DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON, + (long) (js_ctx->p - js_ctx->p_start)); +} + +DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) { + const duk_uint8_t *p; + duk_uint8_t t; + + p = js_ctx->p; + for (;;) { + DUK_ASSERT(p <= js_ctx->p_end); + t = *p; + +#if defined(DUK_USE_JSON_EATWHITE_FASTPATH) + /* This fast path is pretty marginal in practice. + * XXX: candidate for removal. + */ + DUK_ASSERT(duk__json_eatwhite_lookup[0x00] == 0x00); /* end-of-input breaks */ + if (duk__json_eatwhite_lookup[t] == 0) { + break; + } +#else /* DUK_USE_JSON_EATWHITE_FASTPATH */ + if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) { + /* NUL also comes here. Comparison order matters, 0x20 + * is most common whitespace. + */ + break; + } +#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */ + p++; + } + js_ctx->p = p; +} + +DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) { + DUK_ASSERT(js_ctx->p <= js_ctx->p_end); + return *js_ctx->p; +} + +DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) { + DUK_ASSERT(js_ctx->p <= js_ctx->p_end); + return *js_ctx->p++; +} + +DUK_LOCAL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx) { + duk__dec_eat_white(js_ctx); + return duk__dec_get(js_ctx); +} + +/* For JX, expressing the whole unsigned 32-bit range matters. */ +DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) { + duk_small_uint_t i; + duk_uint_fast32_t res = 0; + duk_uint8_t x; + duk_small_int_t t; + + for (i = 0; i < n; i++) { + /* XXX: share helper from lexer; duk_lexer.c / hexval(). */ + + x = duk__dec_get(js_ctx); + DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld", + (long) i, (long) n, (long) res, (long) x)); + + /* x == 0x00 (EOF) causes syntax_error */ + DUK_ASSERT(duk_hex_dectab[0] == -1); + t = duk_hex_dectab[x & 0xff]; + if (DUK_LIKELY(t >= 0)) { + res = (res * 16) + t; + } else { + /* catches EOF and invalid digits */ + goto syntax_error; + } + } + + DUK_DDD(DUK_DDDPRINT("final hex decoded value: %ld", (long) res)); + return res; + + syntax_error: + duk__dec_syntax_error(js_ctx); + DUK_UNREACHABLE(); + return 0; +} + +DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) { + duk_hstring *h; + const duk_uint8_t *p; + duk_uint8_t x, y; + + /* First character has already been eaten and checked by the caller. + * We can scan until a NUL in stridx string because no built-in strings + * have internal NULs. + */ + + DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */ + DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx); + DUK_ASSERT(h != NULL); + + p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1; + DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */ + + for (;;) { + x = *p; + if (x == 0) { + break; + } + y = duk__dec_get(js_ctx); + if (x != y) { + /* Catches EOF of JSON input. */ + goto syntax_error; + } + p++; + } + + return; + + syntax_error: + duk__dec_syntax_error(js_ctx); + DUK_UNREACHABLE(); +} + +DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) { + duk_uint_fast32_t cp; + + /* EOF (-1) will be cast to an unsigned value first + * and then re-cast for the switch. In any case, it + * will match the default case (syntax error). + */ + cp = (duk_uint_fast32_t) duk__dec_get(js_ctx); + switch ((int) cp) { + case DUK_ASC_BACKSLASH: break; + case DUK_ASC_DOUBLEQUOTE: break; + case DUK_ASC_SLASH: break; + case DUK_ASC_LC_T: cp = 0x09; break; + case DUK_ASC_LC_N: cp = 0x0a; break; + case DUK_ASC_LC_R: cp = 0x0d; break; + case DUK_ASC_LC_F: cp = 0x0c; break; + case DUK_ASC_LC_B: cp = 0x08; break; + case DUK_ASC_LC_U: { + cp = duk__dec_decode_hex_escape(js_ctx, 4); + break; + } +#ifdef DUK_USE_JX + case DUK_ASC_UC_U: { + if (js_ctx->flag_ext_custom) { + cp = duk__dec_decode_hex_escape(js_ctx, 8); + } else { + return 1; /* syntax error */ + } + break; + } + case DUK_ASC_LC_X: { + if (js_ctx->flag_ext_custom) { + cp = duk__dec_decode_hex_escape(js_ctx, 2); + } else { + return 1; /* syntax error */ + } + break; + } +#endif /* DUK_USE_JX */ + default: + /* catches EOF (0x00) */ + return 1; /* syntax error */ + } + + DUK_RAW_WRITE_XUTF8(*ext_p, cp); + + return 0; +} + +DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) { + duk_hthread *thr = js_ctx->thr; + duk_context *ctx = (duk_context *) thr; + duk_bufwriter_ctx bw_alloc; + duk_bufwriter_ctx *bw; + duk_uint8_t *q; + + /* '"' was eaten by caller */ + + /* Note that we currently parse -bytes-, not codepoints. + * All non-ASCII extended UTF-8 will encode to bytes >= 0x80, + * so they'll simply pass through (valid UTF-8 or not). + */ + + bw = &bw_alloc; + DUK_BW_INIT_PUSHBUF(js_ctx->thr, bw, DUK__JSON_DECSTR_BUFSIZE); + q = DUK_BW_GET_PTR(js_ctx->thr, bw); + +#if defined(DUK_USE_JSON_DECSTRING_FASTPATH) + for (;;) { + duk_small_uint_t safe; + duk_uint8_t b, x; + const duk_uint8_t *p; + + /* Select a safe loop count where no output checks are + * needed assuming we won't encounter escapes. Input + * bound checks are not necessary as a NUL (guaranteed) + * will cause a SyntaxError before we read out of bounds. + */ + + safe = DUK__JSON_DECSTR_CHUNKSIZE; + + /* Ensure space for 1:1 output plus one escape. */ + q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, safe + DUK_UNICODE_MAX_XUTF8_LENGTH, q); + + p = js_ctx->p; /* temp copy, write back for next loop */ + for (;;) { + if (safe == 0) { + js_ctx->p = p; + break; + } + safe--; + + /* End of input (NUL) goes through slow path and causes SyntaxError. */ + DUK_ASSERT(duk__json_decstr_lookup[0] == 0x00); + + b = *p++; + x = (duk_small_int_t) duk__json_decstr_lookup[b]; + if (DUK_LIKELY(x != 0)) { + /* Fast path, decode as is. */ + *q++ = b; + } else if (b == DUK_ASC_DOUBLEQUOTE) { + js_ctx->p = p; + goto found_quote; + } else if (b == DUK_ASC_BACKSLASH) { + /* We've ensured space for one escaped input; then + * bail out and recheck (this makes escape handling + * quite slow but it's uncommon). + */ + js_ctx->p = p; + if (duk__dec_string_escape(js_ctx, &q) != 0) { + goto syntax_error; + } + break; + } else { + js_ctx->p = p; + goto syntax_error; + } + } + } + found_quote: +#else /* DUK_USE_JSON_DECSTRING_FASTPATH */ + for (;;) { + duk_uint8_t x; + + q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q); + + x = duk__dec_get(js_ctx); + + if (x == DUK_ASC_DOUBLEQUOTE) { + break; + } else if (x == DUK_ASC_BACKSLASH) { + if (duk__dec_string_escape(js_ctx, &q) != 0) { + goto syntax_error; + } + } else if (x < 0x20) { + /* catches EOF (NUL) */ + goto syntax_error; + } else { + *q++ = (duk_uint8_t) x; + } + } +#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */ + + DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q); + duk_to_string(ctx, -1); + + /* [ ... str ] */ + + return; + + syntax_error: + duk__dec_syntax_error(js_ctx); + DUK_UNREACHABLE(); +} + +#ifdef DUK_USE_JX +/* Decode a plain string consisting entirely of identifier characters. + * Used to parse plain keys (e.g. "foo: 123"). + */ +DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) { + duk_hthread *thr = js_ctx->thr; + duk_context *ctx = (duk_context *) thr; + const duk_uint8_t *p; + duk_small_int_t x; + + /* Caller has already eaten the first char so backtrack one byte. */ + + js_ctx->p--; /* safe */ + p = js_ctx->p; + + /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of + * parsing (which is correct except if there are non-shortest encodings). + * There is also no need to check explicitly for end of input buffer as + * the input is NUL padded and NUL will exit the parsing loop. + * + * Because no unescaping takes place, we can just scan to the end of the + * plain string and intern from the input buffer. + */ + + for (;;) { + x = *p; + + /* There is no need to check the first character specially here + * (i.e. reject digits): the caller only accepts valid initial + * characters and won't call us if the first character is a digit. + * This also ensures that the plain string won't be empty. + */ + + if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) { + break; + } + p++; + } + + duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p)); + js_ctx->p = p; + + /* [ ... str ] */ +} +#endif /* DUK_USE_JX */ + +#ifdef DUK_USE_JX +DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) { + duk_hthread *thr = js_ctx->thr; + duk_context *ctx = (duk_context *) thr; + const duk_uint8_t *p; + duk_small_int_t x; + void *voidptr; + + /* Caller has already eaten the first character ('(') which we don't need. */ + + p = js_ctx->p; + + for (;;) { + x = *p; + + /* Assume that the native representation never contains a closing + * parenthesis. + */ + + if (x == DUK_ASC_RPAREN) { + break; + } else if (x <= 0) { + /* NUL term or -1 (EOF), NUL check would suffice */ + goto syntax_error; + } + p++; + } + + /* There is no need to NUL delimit the sscanf() call: trailing garbage is + * ignored and there is always a NUL terminator which will force an error + * if no error is encountered before it. It's possible that the scan + * would scan further than between [js_ctx->p,p[ though and we'd advance + * by less than the scanned value. + * + * Because pointers are platform specific, a failure to scan a pointer + * results in a null pointer which is a better placeholder than a missing + * value or an error. + */ + + voidptr = NULL; + (void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr); + duk_push_pointer(ctx, voidptr); + js_ctx->p = p + 1; /* skip ')' */ + + /* [ ... ptr ] */ + + return; + + syntax_error: + duk__dec_syntax_error(js_ctx); + DUK_UNREACHABLE(); +} +#endif /* DUK_USE_JX */ + +#ifdef DUK_USE_JX +DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) { + duk_hthread *thr = js_ctx->thr; + duk_context *ctx = (duk_context *) thr; + const duk_uint8_t *p; + duk_uint8_t *buf; + duk_size_t src_len; + duk_small_int_t x; + + /* Caller has already eaten the first character ('|') which we don't need. */ + + p = js_ctx->p; + + /* XXX: Would be nice to share the fast path loop from duk_hex_decode() + * and avoid creating a temporary buffer. However, there are some + * differences which prevent trivial sharing: + * + * - Pipe char detection + * - EOF detection + * - Unknown length of input and output + * + * The best approach here would be a bufwriter and a reasonaly sized + * safe inner loop (e.g. 64 output bytes at a time). + */ + + for (;;) { + x = *p; + + /* This loop intentionally does not ensure characters are valid + * ([0-9a-fA-F]) because the hex decode call below will do that. + */ + if (x == DUK_ASC_PIPE) { + break; + } else if (x <= 0) { + /* NUL term or -1 (EOF), NUL check would suffice */ + goto syntax_error; + } + p++; + } + + src_len = (duk_size_t) (p - js_ctx->p); + buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_len); + DUK_ASSERT(buf != NULL); + DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len); + duk_hex_decode(ctx, -1); + + js_ctx->p = p + 1; /* skip '|' */ + + /* [ ... buf ] */ + + return; + + syntax_error: + duk__dec_syntax_error(js_ctx); + DUK_UNREACHABLE(); +} +#endif /* DUK_USE_JX */ + +/* Parse a number, other than NaN or +/- Infinity */ +DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) { + duk_context *ctx = (duk_context *) js_ctx->thr; + const duk_uint8_t *p_start; + const duk_uint8_t *p; + duk_uint8_t x; + duk_small_uint_t s2n_flags; + + DUK_DDD(DUK_DDDPRINT("parse_number")); + + p_start = js_ctx->p; + + /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a + * string for strict number parsing. + */ + + p = js_ctx->p; + for (;;) { + x = *p; + + DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld", + (const void *) p_start, (const void *) p, + (const void *) js_ctx->p_end, (long) x)); + +#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH) + /* This fast path is pretty marginal in practice. + * XXX: candidate for removal. + */ + DUK_ASSERT(duk__json_decnumber_lookup[0x00] == 0x00); /* end-of-input breaks */ + if (duk__json_decnumber_lookup[x] == 0) { + break; + } +#else /* DUK_USE_JSON_DECNUMBER_FASTPATH */ + if (!((x >= DUK_ASC_0 && x <= DUK_ASC_9) || + (x == DUK_ASC_PERIOD || x == DUK_ASC_LC_E || + x == DUK_ASC_UC_E || x == DUK_ASC_MINUS || x == DUK_ASC_PLUS))) { + /* Plus sign must be accepted for positive exponents + * (e.g. '1.5e+2'). This clause catches NULs. + */ + break; + } +#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */ + p++; /* safe, because matched (NUL causes a break) */ + } + js_ctx->p = p; + + DUK_ASSERT(js_ctx->p > p_start); + duk_push_lstring(ctx, (const char *) p_start, (duk_size_t) (p - p_start)); + + s2n_flags = DUK_S2N_FLAG_ALLOW_EXP | + DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */ + DUK_S2N_FLAG_ALLOW_FRAC; + + DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T", + (duk_tval *) duk_get_tval(ctx, -1))); + duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags); + if (duk_is_nan(ctx, -1)) { + duk__dec_syntax_error(js_ctx); + } + DUK_ASSERT(duk_is_number(ctx, -1)); + DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T", + (duk_tval *) duk_get_tval(ctx, -1))); + + /* [ ... num ] */ +} + +DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_require_stack(ctx, DUK_JSON_DEC_REQSTACK); + + /* c recursion check */ + + DUK_ASSERT(js_ctx->recursion_depth >= 0); + DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); + if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { + DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONDEC_RECLIMIT); + } + js_ctx->recursion_depth++; +} + +DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) { + /* c recursion check */ + + DUK_ASSERT(js_ctx->recursion_depth > 0); + DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); + js_ctx->recursion_depth--; +} + +DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_int_t key_count; /* XXX: a "first" flag would suffice */ + duk_uint8_t x; + + DUK_DDD(DUK_DDDPRINT("parse_object")); + + duk__dec_objarr_entry(js_ctx); + + duk_push_object(ctx); + + /* Initial '{' has been checked and eaten by caller. */ + + key_count = 0; + for (;;) { + x = duk__dec_get_nonwhite(js_ctx); + + DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld", + (duk_tval *) duk_get_tval(ctx, -1), + (long) x, (long) key_count)); + + /* handle comma and closing brace */ + + if (x == DUK_ASC_COMMA && key_count > 0) { + /* accept comma, expect new value */ + x = duk__dec_get_nonwhite(js_ctx); + } else if (x == DUK_ASC_RCURLY) { + /* eat closing brace */ + break; + } else if (key_count == 0) { + /* accept anything, expect first value (EOF will be + * caught by key parsing below. + */ + ; + } else { + /* catches EOF (NUL) and initial comma */ + goto syntax_error; + } + + /* parse key and value */ + + if (x == DUK_ASC_DOUBLEQUOTE) { + duk__dec_string(js_ctx); +#ifdef DUK_USE_JX + } else if (js_ctx->flag_ext_custom && + duk_unicode_is_identifier_start((duk_codepoint_t) x)) { + duk__dec_plain_string(js_ctx); +#endif + } else { + goto syntax_error; + } + + /* [ ... obj key ] */ + + x = duk__dec_get_nonwhite(js_ctx); + if (x != DUK_ASC_COLON) { + goto syntax_error; + } + + duk__dec_value(js_ctx); + + /* [ ... obj key val ] */ + + duk_xdef_prop_wec(ctx, -3); + + /* [ ... obj ] */ + + key_count++; + } + + /* [ ... obj ] */ + + DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T", + (duk_tval *) duk_get_tval(ctx, -1))); + + duk__dec_objarr_exit(js_ctx); + return; + + syntax_error: + duk__dec_syntax_error(js_ctx); + DUK_UNREACHABLE(); +} + +DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_uarridx_t arr_idx; + duk_uint8_t x; + + DUK_DDD(DUK_DDDPRINT("parse_array")); + + duk__dec_objarr_entry(js_ctx); + + duk_push_array(ctx); + + /* Initial '[' has been checked and eaten by caller. */ + + arr_idx = 0; + for (;;) { + x = duk__dec_get_nonwhite(js_ctx); + + DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld", + (duk_tval *) duk_get_tval(ctx, -1), + (long) x, (long) arr_idx)); + + /* handle comma and closing bracket */ + + if ((x == DUK_ASC_COMMA) && (arr_idx != 0)) { + /* accept comma, expect new value */ + ; + } else if (x == DUK_ASC_RBRACKET) { + /* eat closing bracket */ + break; + } else if (arr_idx == 0) { + /* accept anything, expect first value (EOF will be + * caught by duk__dec_value() below. + */ + js_ctx->p--; /* backtrack (safe) */ + } else { + /* catches EOF (NUL) and initial comma */ + goto syntax_error; + } + + /* parse value */ + + duk__dec_value(js_ctx); + + /* [ ... arr val ] */ + + duk_xdef_prop_index_wec(ctx, -2, arr_idx); + arr_idx++; + } + + /* Must set 'length' explicitly when using duk_xdef_prop_xxx() to + * set the values. + */ + + duk_set_length(ctx, -1, arr_idx); + + /* [ ... arr ] */ + + DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T", + (duk_tval *) duk_get_tval(ctx, -1))); + + duk__dec_objarr_exit(js_ctx); + return; + + syntax_error: + duk__dec_syntax_error(js_ctx); + DUK_UNREACHABLE(); +} + +DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_uint8_t x; + + x = duk__dec_get_nonwhite(js_ctx); + + DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld", (long) x)); + + /* Note: duk__dec_req_stridx() backtracks one char */ + + if (x == DUK_ASC_DOUBLEQUOTE) { + duk__dec_string(js_ctx); + } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) { +#ifdef DUK_USE_JX + if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) { + duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */ + duk_push_number(ctx, -DUK_DOUBLE_INFINITY); + } else { +#else + { /* unconditional block */ +#endif + /* We already ate 'x', so backup one byte. */ + js_ctx->p--; /* safe */ + duk__dec_number(js_ctx); + } + } else if (x == DUK_ASC_LC_T) { + duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE); + duk_push_true(ctx); + } else if (x == DUK_ASC_LC_F) { + duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE); + duk_push_false(ctx); + } else if (x == DUK_ASC_LC_N) { + duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL); + duk_push_null(ctx); +#ifdef DUK_USE_JX + } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) { + duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED); + duk_push_undefined(ctx); + } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) { + duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN); + duk_push_nan(ctx); + } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) { + duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY); + duk_push_number(ctx, DUK_DOUBLE_INFINITY); + } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) { + duk__dec_pointer(js_ctx); + } else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) { + duk__dec_buffer(js_ctx); +#endif + } else if (x == DUK_ASC_LCURLY) { + duk__dec_object(js_ctx); + } else if (x == DUK_ASC_LBRACKET) { + duk__dec_array(js_ctx); + } else { + /* catches EOF (NUL) */ + goto syntax_error; + } + + duk__dec_eat_white(js_ctx); + + /* [ ... val ] */ + return; + + syntax_error: + duk__dec_syntax_error(js_ctx); + DUK_UNREACHABLE(); +} + +/* Recursive value reviver, implements the Walk() algorithm. No C recursion + * check is done here because the initial parsing step will already ensure + * there is a reasonable limit on C recursion depth and hence object depth. + */ +DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_hobject *h; + duk_uarridx_t i, arr_len; + + DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T", + (long) duk_get_top(ctx), + (duk_tval *) duk_get_tval(ctx, -2), + (duk_tval *) duk_get_tval(ctx, -1))); + + duk_dup_top(ctx); + duk_get_prop(ctx, -3); /* -> [ ... holder name val ] */ + + h = duk_get_hobject(ctx, -1); + if (h != NULL) { + if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) { + arr_len = (duk_uarridx_t) duk_get_length(ctx, -1); + for (i = 0; i < arr_len; i++) { + /* [ ... holder name val ] */ + + DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T", + (long) duk_get_top(ctx), (long) i, (long) arr_len, + (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2), + (duk_tval *) duk_get_tval(ctx, -1))); + + /* XXX: push_uint_string / push_u32_string */ + duk_dup_top(ctx); + duk_push_uint(ctx, (duk_uint_t) i); + duk_to_string(ctx, -1); /* -> [ ... holder name val val ToString(i) ] */ + duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */ + + if (duk_is_undefined(ctx, -1)) { + duk_pop(ctx); + duk_del_prop_index(ctx, -1, i); + } else { + /* XXX: duk_xdef_prop_index_wec() would be more appropriate + * here but it currently makes some assumptions that might + * not hold (e.g. that previous property is not an accessor). + */ + duk_put_prop_index(ctx, -2, i); + } + } + } else { + /* [ ... holder name val ] */ + duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); + while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) { + DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T", + (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -5), + (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3), + (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); + + /* [ ... holder name val enum obj_key ] */ + duk_dup(ctx, -3); + duk_dup(ctx, -2); + + /* [ ... holder name val enum obj_key val obj_key ] */ + duk__dec_reviver_walk(js_ctx); + + /* [ ... holder name val enum obj_key new_elem ] */ + if (duk_is_undefined(ctx, -1)) { + duk_pop(ctx); + duk_del_prop(ctx, -3); + } else { + /* XXX: duk_xdef_prop_index_wec() would be more appropriate + * here but it currently makes some assumptions that might + * not hold (e.g. that previous property is not an accessor). + * + * Using duk_put_prop() works incorrectly with '__proto__' + * if the own property with that name has been deleted. This + * does not happen normally, but a clever reviver can trigger + * that, see complex reviver case in: test-bug-json-parse-__proto__.js. + */ + duk_put_prop(ctx, -4); + } + } + duk_pop(ctx); /* pop enum */ + } + } + + /* [ ... holder name val ] */ + + duk_dup(ctx, js_ctx->idx_reviver); + duk_insert(ctx, -4); /* -> [ ... reviver holder name val ] */ + duk_call_method(ctx, 2); /* -> [ ... res ] */ + + DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T", + (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -1))); +} + +/* + * Stringify implementation. + */ + +#define DUK__EMIT_1(js_ctx,ch) duk__emit_1((js_ctx), (duk_uint_fast8_t) (ch)) +#define DUK__EMIT_2(js_ctx,ch1,ch2) duk__emit_2((js_ctx), (duk_uint_fast8_t) (ch1), (duk_uint_fast8_t) (ch2)) +#define DUK__EMIT_HSTR(js_ctx,h) duk__emit_hstring((js_ctx), (h)) +#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC) +#define DUK__EMIT_CSTR(js_ctx,p) duk__emit_cstring((js_ctx), (p)) +#endif +#define DUK__EMIT_STRIDX(js_ctx,i) duk__emit_stridx((js_ctx), (i)) +#define DUK__UNEMIT_1(js_ctx) duk__unemit_1((js_ctx)) + +DUK_LOCAL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch) { + DUK_BW_WRITE_ENSURE_U8(js_ctx->thr, &js_ctx->bw, ch); +} + +DUK_LOCAL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2) { + DUK_BW_WRITE_ENSURE_U8_2(js_ctx->thr, &js_ctx->bw, ch1, ch2); +} + +DUK_LOCAL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) { + DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h); +} + +#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC) +DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) { + DUK_BW_WRITE_ENSURE_CSTRING(js_ctx->thr, &js_ctx->bw, str); +} +#endif + +DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) { + duk_hstring *h; + + DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */ + DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); + h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx); + DUK_ASSERT(h != NULL); + + DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h); +} + +DUK_LOCAL void duk__unemit_1(duk_json_enc_ctx *js_ctx) { + DUK_ASSERT(DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw) >= 1); + DUK_BW_ADD_PTR(js_ctx->thr, &js_ctx->bw, -1); +} + +#define DUK__MKESC(nybbles,esc1,esc2) \ + (((duk_uint_fast32_t) (nybbles)) << 16) | \ + (((duk_uint_fast32_t) (esc1)) << 8) | \ + ((duk_uint_fast32_t) (esc2)) + +DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q) { + duk_uint_fast32_t tmp; + duk_small_uint_t dig; + + DUK_UNREF(js_ctx); + + /* Caller ensures space for at least DUK__JSON_MAX_ESC_LEN. */ + + /* Select appropriate escape format automatically, and set 'tmp' to a + * value encoding both the escape format character and the nybble count: + * + * (nybble_count << 16) | (escape_char1) | (escape_char2) + */ + +#ifdef DUK_USE_JX + if (DUK_LIKELY(cp < 0x100UL)) { + if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) { + tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X); + } else { + tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U); + } + } else +#endif + if (DUK_LIKELY(cp < 0x10000UL)) { + tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U); + } else { +#ifdef DUK_USE_JX + if (DUK_LIKELY(js_ctx->flag_ext_custom)) { + tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U); + } else +#endif + { + /* In compatible mode and standard JSON mode, output + * something useful for non-BMP characters. This won't + * roundtrip but will still be more or less readable and + * more useful than an error. + */ + tmp = DUK__MKESC(8, DUK_ASC_UC_U, DUK_ASC_PLUS); + } + } + + *q++ = (duk_uint8_t) ((tmp >> 8) & 0xff); + *q++ = (duk_uint8_t) (tmp & 0xff); + + tmp = tmp >> 16; + while (tmp > 0) { + tmp--; + dig = (duk_small_uint_t) ((cp >> (4 * tmp)) & 0x0f); + *q++ = duk_lc_digits[dig]; + } + + return q; +} + +DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) { + const duk_int8_t *p, *p_start, *p_end; /* Note: intentionally signed. */ + duk_size_t k_len; + duk_codepoint_t cp; + + DUK_ASSERT(k != NULL); + + /* Accept ASCII strings which conform to identifier requirements + * as being emitted without key quotes. Since we only accept ASCII + * there's no need for actual decoding: 'p' is intentionally signed + * so that bytes >= 0x80 extend to negative values and are rejected + * as invalid identifier codepoints. + */ + + if (js_ctx->flag_avoid_key_quotes) { + k_len = DUK_HSTRING_GET_BYTELEN(k); + p_start = (const duk_int8_t *) DUK_HSTRING_GET_DATA(k); + p_end = p_start + k_len; + p = p_start; + + if (p == p_end) { + /* Zero length string is not accepted without quotes */ + goto quote_normally; + } + cp = (duk_codepoint_t) (*p++); + if (DUK_UNLIKELY(!duk_unicode_is_identifier_start(cp))) { + goto quote_normally; + } + while (p < p_end) { + cp = (duk_codepoint_t) (*p++); + if (DUK_UNLIKELY(!duk_unicode_is_identifier_part(cp))) { + goto quote_normally; + } + } + + /* This seems faster than emitting bytes one at a time and + * then potentially rewinding. + */ + DUK__EMIT_HSTR(js_ctx, k); + return; + } + + quote_normally: + duk__enc_quote_string(js_ctx, k); +} + +/* The Quote(value) operation: quote a string. + * + * Stack policy: [ ] -> [ ]. + */ + +DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) { + duk_hthread *thr = js_ctx->thr; + const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp; + duk_uint8_t *q; + duk_ucodepoint_t cp; /* typed for duk_unicode_decode_xutf8() */ + + DUK_DDD(DUK_DDDPRINT("duk__enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str)); + + DUK_ASSERT(h_str != NULL); + p_start = DUK_HSTRING_GET_DATA(h_str); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str); + p = p_start; + + DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE); + + /* Encode string in small chunks, estimating the maximum expansion so that + * there's no need to ensure space while processing the chunk. + */ + + while (p < p_end) { + duk_size_t left, now, space; + + left = (duk_size_t) (p_end - p); + now = (left > DUK__JSON_ENCSTR_CHUNKSIZE ? + DUK__JSON_ENCSTR_CHUNKSIZE : left); + + /* Maximum expansion per input byte is 6: + * - invalid UTF-8 byte causes "\uXXXX" to be emitted (6/1 = 6). + * - 2-byte UTF-8 encodes as "\uXXXX" (6/2 = 3). + * - 4-byte UTF-8 encodes as "\Uxxxxxxxx" (10/4 = 2.5). + */ + space = now * 6; + q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space); + + p_now = p + now; + + while (p < p_now) { +#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH) + duk_uint8_t b; + + b = duk__json_quotestr_lookup[*p++]; + if (DUK_LIKELY(b < 0x80)) { + /* Most input bytes go through here. */ + *q++ = b; + } else if (b >= 0xa0) { + *q++ = DUK_ASC_BACKSLASH; + *q++ = (duk_uint8_t) (b - 0x80); + } else if (b == 0x80) { + cp = (duk_ucodepoint_t) (*(p - 1)); + q = duk__emit_esc_auto_fast(js_ctx, cp, q); + } else if (b == 0x7f && js_ctx->flag_ascii_only) { + /* 0x7F is special */ + DUK_ASSERT(b == 0x81); + cp = (duk_ucodepoint_t) 0x7f; + q = duk__emit_esc_auto_fast(js_ctx, cp, q); + } else { + DUK_ASSERT(b == 0x81); + p--; + + /* slow path is shared */ +#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ + cp = *p; + + if (DUK_LIKELY(cp <= 0x7f)) { + /* ascii fast path: avoid decoding utf-8 */ + p++; + if (cp == 0x22 || cp == 0x5c) { + /* double quote or backslash */ + *q++ = DUK_ASC_BACKSLASH; + *q++ = (duk_uint8_t) cp; + } else if (cp < 0x20) { + duk_uint_fast8_t esc_char; + + /* This approach is a bit shorter than a straight + * if-else-ladder and also a bit faster. + */ + if (cp < (sizeof(duk__json_quotestr_esc) / sizeof(duk_uint8_t)) && + (esc_char = duk__json_quotestr_esc[cp]) != 0) { + *q++ = DUK_ASC_BACKSLASH; + *q++ = (duk_uint8_t) esc_char; + } else { + q = duk__emit_esc_auto_fast(js_ctx, cp, q); + } + } else if (cp == 0x7f && js_ctx->flag_ascii_only) { + q = duk__emit_esc_auto_fast(js_ctx, cp, q); + } else { + /* any other printable -> as is */ + *q++ = (duk_uint8_t) cp; + } + } else { + /* slow path is shared */ +#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ + + /* slow path decode */ + + /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly + * and go forward one byte. This is of course very lossy, but allows some kind + * of output to be produced even for internal strings which don't conform to + * XUTF-8. All standard Ecmascript strings are always CESU-8, so this behavior + * does not violate the Ecmascript specification. The behavior is applied to + * all modes, including Ecmascript standard JSON. Because the current XUTF-8 + * decoding is not very strict, this behavior only really affects initial bytes + * and truncated codepoints. + * + * Another alternative would be to scan forwards to start of next codepoint + * (or end of input) and emit just one replacement codepoint. + */ + + p_tmp = p; + if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) { + /* Decode failed. */ + cp = *p_tmp; + p = p_tmp + 1; + } + +#ifdef DUK_USE_NONSTD_JSON_ESC_U2028_U2029 + if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) { +#else + if (js_ctx->flag_ascii_only) { +#endif + q = duk__emit_esc_auto_fast(js_ctx, cp, q); + } else { + /* as is */ + DUK_RAW_WRITE_XUTF8(q, cp); + } + } + } + + DUK_BW_SET_PTR(thr, &js_ctx->bw, q); + } + + DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE); +} + +/* Encode a double (checked by caller) from stack top. Stack top may be + * replaced by serialized string but is not popped (caller does that). + */ +DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) { + duk_hthread *thr; + duk_context *ctx; + duk_tval *tv; + duk_double_t d; + duk_small_int_t c; + duk_small_int_t s; + duk_small_uint_t stridx; + duk_small_uint_t n2s_flags; + duk_hstring *h_str; + + DUK_ASSERT(js_ctx != NULL); + thr = js_ctx->thr; + DUK_ASSERT(thr != NULL); + ctx = (duk_context *) thr; + + /* Caller must ensure 'tv' is indeed a double and not a fastint! */ + tv = DUK_GET_TVAL_NEGIDX(ctx, -1); + DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); + d = DUK_TVAL_GET_DOUBLE(tv); + + c = (duk_small_int_t) DUK_FPCLASSIFY(d); + s = (duk_small_int_t) DUK_SIGNBIT(d); + DUK_UNREF(s); + + if (DUK_LIKELY(!(c == DUK_FP_INFINITE || c == DUK_FP_NAN))) { + DUK_ASSERT(DUK_ISFINITE(d)); + +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + /* Negative zero needs special handling in JX/JC because + * it would otherwise serialize to '0', not '-0'. + */ + if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 && + (js_ctx->flag_ext_custom_or_compatible))) { + duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */ + } else +#endif /* DUK_USE_JX || DUK_USE_JC */ + { + n2s_flags = 0; + /* [ ... number ] -> [ ... string ] */ + duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags); + } + h_str = duk_to_hstring(ctx, -1); + DUK_ASSERT(h_str != NULL); + DUK__EMIT_HSTR(js_ctx, h_str); + return; + } + +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | + DUK_JSON_FLAG_EXT_COMPATIBLE))) { + stridx = DUK_STRIDX_LC_NULL; + } else if (c == DUK_FP_NAN) { + stridx = js_ctx->stridx_custom_nan; + } else if (s == 0) { + stridx = js_ctx->stridx_custom_posinf; + } else { + stridx = js_ctx->stridx_custom_neginf; + } +#else + stridx = DUK_STRIDX_LC_NULL; +#endif + DUK__EMIT_STRIDX(js_ctx, stridx); +} + +#if defined(DUK_USE_FASTINT) +/* Encode a fastint from duk_tval ptr, no value stack effects. */ +DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) { + duk_int64_t v; + + /* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328 + * (16 chars long), longest signed 64-bit value is -2^63 = -9223372036854775808 + * (20 chars long). Alloc space for 64-bit range to be safe. + */ + duk_uint8_t buf[20 + 1]; + + /* Caller must ensure 'tv' is indeed a fastint! */ + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); + v = DUK_TVAL_GET_FASTINT(tv); + + /* XXX: There are no format strings in duk_config.h yet, could add + * one for formatting duk_int64_t. For now, assumes "%lld" and that + * "long long" type exists. Could also rely on C99 directly but that + * won't work for older MSVC. + */ + DUK_SPRINTF((char *) buf, "%lld", (long long) v); + DUK__EMIT_CSTR(js_ctx, (const char *) buf); +} +#endif + +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) +#if defined(DUK_USE_HEX_FASTPATH) +DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) { + duk_uint8_t *q; + duk_uint16_t *q16; + duk_small_uint_t x; + duk_size_t i, len_safe; +#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) + duk_bool_t shift_dst; +#endif + + /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2. + * For platforms where unaligned accesses are not allowed, shift 'dst' + * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result + * in place. The faster encoding loop makes up the difference. + * There's always space for one extra byte because a terminator always + * follows the hex data and that's been accounted for by the caller. + */ + +#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) + q16 = (duk_uint16_t *) (void *) dst; +#else + shift_dst = (duk_bool_t) (((duk_size_t) dst) & 0x01U); + if (shift_dst) { + DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1")); + q16 = (duk_uint16_t *) (void *) (dst + 1); + } else { + DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned")); + q16 = (duk_uint16_t *) (void *) dst; + } + DUK_ASSERT((((duk_size_t) q16) & 0x01U) == 0); +#endif + + len_safe = src_len & ~0x03U; + for (i = 0; i < len_safe; i += 4) { + q16[0] = duk_hex_enctab[src[i]]; + q16[1] = duk_hex_enctab[src[i + 1]]; + q16[2] = duk_hex_enctab[src[i + 2]]; + q16[3] = duk_hex_enctab[src[i + 3]]; + q16 += 4; + } + q = (duk_uint8_t *) q16; + +#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) + if (shift_dst) { + q--; + DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe); + DUK_ASSERT(dst + 2 * len_safe == q); + } +#endif + + for (; i < src_len; i++) { + x = src[i]; + *q++ = duk_lc_digits[x >> 4]; + *q++ = duk_lc_digits[x & 0x0f]; + } + + return q; +} +#else /* DUK_USE_HEX_FASTPATH */ +DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) { + const duk_uint8_t *p; + const duk_uint8_t *p_end; + duk_uint8_t *q; + duk_small_uint_t x; + + p = src; + p_end = src + src_len; + q = dst; + while (p != p_end) { + x = *p++; + *q++ = duk_lc_digits[x >> 4]; + *q++ = duk_lc_digits[x & 0x0f]; + } + + return q; +} +#endif /* DUK_USE_HEX_FASTPATH */ + +DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) { + duk_hthread *thr; + duk_uint8_t *q; + duk_size_t space; + + thr = js_ctx->thr; + + DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */ + DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible); + + /* Buffer values are encoded in (lowercase) hex to make the + * binary data readable. Base64 or similar would be more + * compact but less readable, and the point of JX/JC + * variants is to be as useful to a programmer as possible. + */ + + /* The #ifdef clutter here needs to handle the three cases: + * (1) JX+JC, (2) JX only, (3) JC only. + */ + + /* Note: space must cater for both JX and JC. */ + space = 9 + buf_len * 2 + 2; + DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL); + DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */ + q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space); + +#if defined(DUK_USE_JX) && defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom) +#endif +#if defined(DUK_USE_JX) + { + *q++ = DUK_ASC_PIPE; + q = duk__enc_buffer_data_hex(buf_data, buf_len, q); + *q++ = DUK_ASC_PIPE; + + } +#endif +#if defined(DUK_USE_JX) && defined(DUK_USE_JC) + else +#endif +#if defined(DUK_USE_JC) + { + DUK_ASSERT(js_ctx->flag_ext_compatible); + DUK_MEMCPY((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */ + q += 9; + q = duk__enc_buffer_data_hex(buf_data, buf_len, q); + *q++ = DUK_ASC_DOUBLEQUOTE; + *q++ = DUK_ASC_RCURLY; + } +#endif + + DUK_BW_SET_PTR(thr, &js_ctx->bw, q); +} + +DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { + duk__enc_buffer_data(js_ctx, + (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h), + (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); +} +#endif /* DUK_USE_JX || DUK_USE_JC */ + +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) +DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { + char buf[64]; /* XXX: how to figure correct size? */ + const char *fmt; + + DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */ + DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible); + + DUK_MEMZERO(buf, sizeof(buf)); + + /* The #ifdef clutter here needs to handle the three cases: + * (1) JX+JC, (2) JX only, (3) JC only. + */ +#if defined(DUK_USE_JX) && defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom) +#endif +#if defined(DUK_USE_JX) + { + fmt = ptr ? "(%p)" : "(null)"; + } +#endif +#if defined(DUK_USE_JX) && defined(DUK_USE_JC) + else +#endif +#if defined(DUK_USE_JC) + { + DUK_ASSERT(js_ctx->flag_ext_compatible); + fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}"; + } +#endif + + /* When ptr == NULL, the format argument is unused. */ + DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */ + DUK__EMIT_CSTR(js_ctx, buf); +} +#endif /* DUK_USE_JX || DUK_USE_JC */ + +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) +DUK_LOCAL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj) { + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + if (h_bufobj->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) { + DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); + } else { + /* Handle both full and partial slice (as long as covered). */ + duk__enc_buffer_data(js_ctx, + (duk_uint8_t *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj), + (duk_size_t) h_bufobj->length); + } +} +#endif /* DUK_USE_JX || DUK_USE_JC */ + +/* Indent helper. Calling code relies on js_ctx->recursion_depth also being + * directly related to indent depth. + */ +#if defined(DUK_USE_PREFER_SIZE) +DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) { + DUK_ASSERT(js_ctx->h_gap != NULL); + DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */ + + DUK__EMIT_1(js_ctx, 0x0a); + while (depth-- > 0) { + DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap); + } +} +#else /* DUK_USE_PREFER_SIZE */ +DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) { + const duk_uint8_t *gap_data; + duk_size_t gap_len; + duk_size_t avail_bytes; /* bytes of indent available for copying */ + duk_size_t need_bytes; /* bytes of indent still needed */ + duk_uint8_t *p_start; + duk_uint8_t *p; + + DUK_ASSERT(js_ctx->h_gap != NULL); + DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */ + + DUK__EMIT_1(js_ctx, 0x0a); + if (DUK_UNLIKELY(depth == 0)) { + return; + } + + /* To handle deeper indents efficiently, make use of copies we've + * already emitted. In effect we can emit a sequence of 1, 2, 4, + * 8, etc copies, and then finish the last run. Byte counters + * avoid multiply with gap_len on every loop. + */ + + gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap); + gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap); + DUK_ASSERT(gap_len > 0); + + need_bytes = gap_len * depth; + p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes); + p_start = p; + + DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len); + p += gap_len; + avail_bytes = gap_len; + DUK_ASSERT(need_bytes >= gap_len); + need_bytes -= gap_len; + + while (need_bytes >= avail_bytes) { + DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes); + p += avail_bytes; + need_bytes -= avail_bytes; + avail_bytes <<= 1; + } + + DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */ + DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes); + p += need_bytes; + /*avail_bytes += need_bytes*/ + + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p); +} +#endif /* DUK_USE_PREFER_SIZE */ + +/* Shared entry handling for object/array serialization. */ +DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_hobject *h_target; + duk_uint_fast32_t i, n; + + *entry_top = duk_get_top(ctx); + + duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK); + + /* Loop check using a hybrid approach: a fixed-size visited[] array + * with overflow in a loop check object. + */ + + h_target = duk_get_hobject(ctx, -1); /* object or array */ + DUK_ASSERT(h_target != NULL); + + n = js_ctx->recursion_depth; + if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) { + n = DUK_JSON_ENC_LOOPARRAY; + } + for (i = 0; i < n; i++) { + if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) { + DUK_DD(DUK_DDPRINT("slow path loop detect")); + DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT); + } + } + if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { + js_ctx->visiting[js_ctx->recursion_depth] = h_target; + } else { + duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target); + duk_dup_top(ctx); /* -> [ ... voidp voidp ] */ + if (duk_has_prop(ctx, js_ctx->idx_loop)) { + DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT); + } + duk_push_true(ctx); /* -> [ ... voidp true ] */ + duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */ + } + + /* C recursion check. */ + + DUK_ASSERT(js_ctx->recursion_depth >= 0); + DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); + if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { + DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONENC_RECLIMIT); + } + js_ctx->recursion_depth++; + + DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T", + (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop))); +} + +/* Shared exit handling for object/array serialization. */ +DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_hobject *h_target; + + /* C recursion check. */ + + DUK_ASSERT(js_ctx->recursion_depth > 0); + DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); + js_ctx->recursion_depth--; + + /* Loop check. */ + + h_target = duk_get_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */ + DUK_ASSERT(h_target != NULL); + + if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { + /* Previous entry was inside visited[], nothing to do. */ + } else { + duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target); + duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */ + } + + /* Restore stack top after unbalanced code paths. */ + duk_set_top(ctx, *entry_top); + + DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T", + (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop))); +} + +/* The JO(value) operation: encode object. + * + * Stack policy: [ object ] -> [ object ]. + */ +DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_hstring *h_key; + duk_idx_t entry_top; + duk_idx_t idx_obj; + duk_idx_t idx_keys; + duk_bool_t emitted; + duk_uarridx_t arr_len, i; + duk_size_t prev_size; + + DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1))); + + duk__enc_objarr_entry(js_ctx, &entry_top); + + idx_obj = entry_top - 1; + + if (js_ctx->idx_proplist >= 0) { + idx_keys = js_ctx->idx_proplist; + } else { + /* XXX: would be nice to enumerate an object at specified index */ + duk_dup(ctx, idx_obj); + (void) duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */ + idx_keys = duk_require_normalize_index(ctx, -1); + /* leave stack unbalanced on purpose */ + } + + DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T", + (long) idx_keys, (duk_tval *) duk_get_tval(ctx, idx_keys))); + + /* Steps 8-10 have been merged to avoid a "partial" variable. */ + + DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); + + /* XXX: keys is an internal object with all keys to be processed + * in its (gapless) array part. Because nobody can touch the keys + * object, we could iterate its array part directly (keeping in mind + * that it can be reallocated). + */ + + arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_keys); + emitted = 0; + for (i = 0; i < arr_len; i++) { + duk_get_prop_index(ctx, idx_keys, i); /* -> [ ... key ] */ + + DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T", + (duk_tval *) duk_get_tval(ctx, idx_obj), + (duk_tval *) duk_get_tval(ctx, -1))); + + h_key = duk_get_hstring(ctx, -1); + DUK_ASSERT(h_key != NULL); + + prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw); + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + duk__enc_key_autoquote(js_ctx, h_key); + DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE); + } else { + duk__enc_key_autoquote(js_ctx, h_key); + DUK__EMIT_1(js_ctx, DUK_ASC_COLON); + } + + /* [ ... key ] */ + + if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_obj) == 0)) { + /* Value would yield 'undefined', so skip key altogether. + * Side effects have already happened. + */ + DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size); + } else { + DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); + emitted = 1; + } + + /* [ ... ] */ + } + + if (emitted) { + DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); + DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1); + } + } + DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); + + duk__enc_objarr_exit(js_ctx, &entry_top); + + DUK_ASSERT_TOP(ctx, entry_top); +} + +/* The JA(value) operation: encode array. + * + * Stack policy: [ array ] -> [ array ]. + */ +DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_idx_t entry_top; + duk_idx_t idx_arr; + duk_bool_t emitted; + duk_uarridx_t i, arr_len; + + DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T", + (duk_tval *) duk_get_tval(ctx, -1))); + + duk__enc_objarr_entry(js_ctx, &entry_top); + + idx_arr = entry_top - 1; + + /* Steps 8-10 have been merged to avoid a "partial" variable. */ + + DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET); + + arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr); + emitted = 0; + for (i = 0; i < arr_len; i++) { + DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld", + (duk_tval *) duk_get_tval(ctx, idx_arr), + (long) i, (long) arr_len)); + + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + } + + /* XXX: duk_push_uint_string() */ + duk_push_uint(ctx, (duk_uint_t) i); + duk_to_string(ctx, -1); /* -> [ ... key ] */ + + /* [ ... key ] */ + + if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_arr) == 0)) { + /* Value would normally be omitted, replace with 'null'. */ + DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); + } else { + ; + } + + /* [ ... ] */ + + DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); + emitted = 1; + } + + if (emitted) { + DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); + DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1); + } + } + DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET); + + duk__enc_objarr_exit(js_ctx, &entry_top); + + DUK_ASSERT_TOP(ctx, entry_top); +} + +/* The Str(key, holder) operation. + * + * Stack policy: [ ... key ] -> [ ... ] + */ +DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) { + duk_context *ctx = (duk_context *) js_ctx->thr; + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *h_tmp; + duk_tval *tv; + duk_tval *tv_holder; + duk_tval *tv_key; + duk_small_int_t c; + + DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T", + (long) idx_holder, (duk_tval *) duk_get_tval(ctx, idx_holder), + (duk_tval *) duk_get_tval(ctx, -1))); + + DUK_UNREF(thr); + + tv_holder = DUK_GET_TVAL_POSIDX(ctx, idx_holder); + DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder)); + tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1); + DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key)); + (void) duk_hobject_getprop(thr, tv_holder, tv_key); + + /* -> [ ... key val ] */ + + DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1))); + + h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1); + if (h_tmp != NULL) { + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_JSON); + h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1); /* toJSON() can also be a lightfunc */ + + if (h_tmp != NULL && DUK_HOBJECT_IS_CALLABLE(h_tmp)) { + DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it")); + /* XXX: duk_dup_unvalidated(ctx, -2) etc. */ + duk_dup(ctx, -2); /* -> [ ... key val toJSON val ] */ + duk_dup(ctx, -4); /* -> [ ... key val toJSON val key ] */ + duk_call_method(ctx, 1); /* -> [ ... key val val' ] */ + duk_remove(ctx, -2); /* -> [ ... key val' ] */ + } else { + duk_pop(ctx); /* -> [ ... key val ] */ + } + } + + /* [ ... key val ] */ + + DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1))); + + if (js_ctx->h_replacer) { + /* XXX: Here a "slice copy" would be useful. */ + DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer")); + duk_push_hobject(ctx, js_ctx->h_replacer); /* -> [ ... key val replacer ] */ + duk_dup(ctx, idx_holder); /* -> [ ... key val replacer holder ] */ + duk_dup(ctx, -4); /* -> [ ... key val replacer holder key ] */ + duk_dup(ctx, -4); /* -> [ ... key val replacer holder key val ] */ + duk_call_method(ctx, 2); /* -> [ ... key val val' ] */ + duk_remove(ctx, -2); /* -> [ ... key val' ] */ + } + + /* [ ... key val ] */ + + DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1))); + + tv = DUK_GET_TVAL_NEGIDX(ctx, -1); + if (DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *h; + + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + + if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + duk_hbufferobject *h_bufobj; + h_bufobj = (duk_hbufferobject *) h; + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + /* Conceptually we'd extract the plain underlying buffer + * or its slice and then do a type mask check below to + * see if we should reject it. Do the mask check here + * instead to avoid making a copy of the buffer slice. + */ + + if (js_ctx->mask_for_undefined & DUK_TYPE_MASK_BUFFER) { + DUK_DDD(DUK_DDDPRINT("-> bufferobject (-> plain buffer) will result in undefined (type mask check)")); + goto pop2_undef; + } + DUK_DDD(DUK_DDDPRINT("-> bufferobject won't result in undefined, encode directly")); + duk__enc_bufferobject(js_ctx, h_bufobj); + goto pop2_emitted; +#else + DUK_DDD(DUK_DDDPRINT("no JX/JC support, bufferobject/buffer will always result in undefined")); + goto pop2_undef; +#endif + } else { + c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h); + switch ((int) c) { + case DUK_HOBJECT_CLASS_NUMBER: { + DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()")); + duk_to_number(ctx, -1); + /* The coercion potentially invokes user .valueOf() and .toString() + * but can't result in a function value because [[DefaultValue]] would + * reject such a result: test-dev-json-stringify-coercion-1.js. + */ + DUK_ASSERT(!duk_is_callable(ctx, -1)); + break; + } + case DUK_HOBJECT_CLASS_STRING: { + DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()")); + duk_to_string(ctx, -1); + /* Same coercion behavior as for Number. */ + DUK_ASSERT(!duk_is_callable(ctx, -1)); + break; + } +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + case DUK_HOBJECT_CLASS_POINTER: +#endif + case DUK_HOBJECT_CLASS_BOOLEAN: { + DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value")); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); + duk_remove(ctx, -2); + break; + } + default: { + /* Normal object which doesn't get automatically coerced to a + * primitive value. Functions are checked for specially. The + * primitive value coercions for Number, String, Pointer, and + * Boolean can't result in functions so suffices to check here. + */ + DUK_ASSERT(h != NULL); + if (DUK_HOBJECT_IS_CALLABLE(h)) { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | + DUK_JSON_FLAG_EXT_COMPATIBLE)) { + /* We only get here when doing non-standard JSON encoding */ + DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format")); + DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); + goto pop2_emitted; + } else { + DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)")); + goto pop2_undef; + } +#else /* DUK_USE_JX || DUK_USE_JC */ + DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)")); + goto pop2_undef; +#endif /* DUK_USE_JX || DUK_USE_JC */ + } + } + } /* end switch */ + } + } + + /* [ ... key val ] */ + + DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1))); + + if (duk_check_type_mask(ctx, -1, js_ctx->mask_for_undefined)) { + /* will result in undefined */ + DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)")); + goto pop2_undef; + } + tv = DUK_GET_TVAL_NEGIDX(ctx, -1); + + switch (DUK_TVAL_GET_TAG(tv)) { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + /* When JX/JC not in use, the type mask above will avoid this case if needed. */ + case DUK_TAG_UNDEFINED: { + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); + break; + } +#endif + case DUK_TAG_NULL: { + DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); + break; + } + case DUK_TAG_BOOLEAN: { + DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ? + DUK_STRIDX_TRUE : DUK_STRIDX_FALSE); + break; + } +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + /* When JX/JC not in use, the type mask above will avoid this case if needed. */ + case DUK_TAG_POINTER: { + duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv)); + break; + } +#endif /* DUK_USE_JX || DUK_USE_JC */ + case DUK_TAG_STRING: { + duk_hstring *h = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h != NULL); + + duk__enc_quote_string(js_ctx, h); + break; + } + case DUK_TAG_OBJECT: { + duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + + /* Function values are handled completely above (including + * coercion results): + */ + DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h)); + + if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) { + duk__enc_array(js_ctx); + } else { + duk__enc_object(js_ctx); + } + break; + } +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + /* When JX/JC not in use, the type mask above will avoid this case if needed. */ + case DUK_TAG_BUFFER: { + duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + break; + } +#endif /* DUK_USE_JX || DUK_USE_JC */ + case DUK_TAG_LIGHTFUNC: { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + /* We only get here when doing non-standard JSON encoding */ + DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); +#else + /* Standard JSON omits functions */ + DUK_UNREACHABLE(); +#endif + break; + } +#if defined(DUK_USE_FASTINT) + case DUK_TAG_FASTINT: + /* Number serialization has a significant impact relative to + * other fast path code, so careful fast path for fastints. + */ + duk__enc_fastint_tval(js_ctx, tv); + break; +#endif + default: { + /* number */ + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + /* XXX: A fast path for usual integers would be useful when + * fastint support is not enabled. + */ + duk__enc_double(js_ctx); + break; + } + } + + pop2_emitted: + duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */ + return 1; /* emitted */ + + pop2_undef: + duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */ + return 0; /* not emitted */ +} + +/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */ +DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) { + duk_hobject *h; + duk_small_int_t c; + + DUK_ASSERT(tv != NULL); + if (DUK_TVAL_IS_STRING(tv) || DUK_TVAL_IS_NUMBER(tv)) { + return 1; + } else if (DUK_TVAL_IS_OBJECT(tv)) { + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h); + if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) { + return 1; + } + } + + return 0; +} + +/* + * JSON.stringify() fast path + * + * Otherwise supports full JSON, JX, and JC features, but bails out on any + * possible side effect which might change the value being serialized. The + * fast path can take advantage of the fact that the value being serialized + * is unchanged so that we can walk directly through property tables etc. + */ + +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, duk_tval *tv) { + duk_uint_fast32_t i, n; + + DUK_DDD(DUK_DDDPRINT("stringify fast: %!T", tv)); + + DUK_ASSERT(js_ctx != NULL); + DUK_ASSERT(js_ctx->thr != NULL); + +#if 0 /* disabled for now */ + restart_match: +#endif + + DUK_ASSERT(tv != NULL); + + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNDEFINED: { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) { + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); + break; + } else { + goto emit_undefined; + } +#else + goto emit_undefined; +#endif + } + case DUK_TAG_NULL: { + DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); + break; + } + case DUK_TAG_BOOLEAN: { + DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ? + DUK_STRIDX_TRUE : DUK_STRIDX_FALSE); + break; + } + case DUK_TAG_STRING: { + duk_hstring *h; + + h = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h != NULL); + duk__enc_quote_string(js_ctx, h); + break; + } + case DUK_TAG_OBJECT: { + duk_hobject *obj; + duk_tval *tv_val; + duk_bool_t emitted = 0; + duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef, + c_func, c_bufobj, c_object; + + /* For objects JSON.stringify() only looks for own, enumerable + * properties which is nice for the fast path here. + * + * For arrays JSON.stringify() uses [[Get]] so it will actually + * inherit properties during serialization! This fast path + * supports gappy arrays as long as there's no actual inherited + * property (which might be a getter etc). + * + * Since recursion only happens for objects, we can have both + * recursion and loop checks here. We use a simple, depth-limited + * loop check in the fast path because the object-based tracking + * is very slow (when tested, it accounted for 50% of fast path + * execution time for input data with a lot of small objects!). + */ + + /* XXX: for real world code, could just ignore array inheritance + * and only look at array own properties. + */ + + /* We rely on a few object flag / class number relationships here, + * assert for them. + */ + + obj = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(obj != NULL); + DUK_ASSERT_HOBJECT_VALID(obj); + + /* Once recursion depth is increased, exit path must decrease + * it (though it's OK to abort the fast path). + */ + + DUK_ASSERT(js_ctx->recursion_depth >= 0); + DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); + if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { + DUK_DD(DUK_DDPRINT("fast path recursion limit")); + DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT); + } + + for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) { + if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) { + DUK_DD(DUK_DDPRINT("fast path loop detect")); + DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT); + } + } + + /* Guaranteed by recursion_limit setup so we don't have to + * check twice. + */ + DUK_ASSERT(js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY); + js_ctx->visiting[js_ctx->recursion_depth] = obj; + js_ctx->recursion_depth++; + + /* If object has a .toJSON() property, we can't be certain + * that it wouldn't mutate any value arbitrarily, so bail + * out of the fast path. + * + * If an object is a Proxy we also can't avoid side effects + * so abandon. + */ + /* XXX: non-callable .toJSON() doesn't need to cause an abort + * but does at the moment, probably not worth fixing. + */ + if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) || + DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) { + DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path")); + goto abort_fastpath; + } + + /* We could use a switch-case for the class number but it turns out + * a small if-else ladder on class masks is better. The if-ladder + * should be in order of relevancy. + */ + + /* XXX: move masks to js_ctx? they don't change during one + * fast path invocation. + */ + DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31); +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom_or_compatible) { + c_all = DUK_HOBJECT_CMASK_ALL; + c_array = DUK_HOBJECT_CMASK_ARRAY; + c_unbox = DUK_HOBJECT_CMASK_NUMBER | + DUK_HOBJECT_CMASK_STRING | + DUK_HOBJECT_CMASK_BOOLEAN | + DUK_HOBJECT_CMASK_POINTER; + c_func = DUK_HOBJECT_CMASK_FUNCTION; + c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS; + c_undef = 0; + c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef); + } + else +#endif + { + c_all = DUK_HOBJECT_CMASK_ALL; + c_array = DUK_HOBJECT_CMASK_ARRAY; + c_unbox = DUK_HOBJECT_CMASK_NUMBER | + DUK_HOBJECT_CMASK_STRING | + DUK_HOBJECT_CMASK_BOOLEAN; + c_func = 0; + c_bufobj = 0; + c_undef = DUK_HOBJECT_CMASK_FUNCTION | + DUK_HOBJECT_CMASK_POINTER | + DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS; + c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef); + } + + c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj); + if (c_bit & c_object) { + /* All other object types. */ + DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); + + /* A non-Array object should not have an array part in practice. + * But since it is supported internally (and perhaps used at some + * point), check and abandon if that's the case. + */ + if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) { + DUK_DD(DUK_DDPRINT("non-Array object has array part, abort fast path")); + goto abort_fastpath; + } + + for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(obj); i++) { + duk_hstring *k; + duk_size_t prev_size; + + k = DUK_HOBJECT_E_GET_KEY(js_ctx->thr->heap, obj, i); + if (!k) { + continue; + } + if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) { + continue; + } + if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(js_ctx->thr->heap, obj, i)) { + /* Getter might have arbitrary side effects, + * so bail out. + */ + DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path")); + goto abort_fastpath; + } + if (DUK_HSTRING_HAS_INTERNAL(k)) { + continue; + } + + tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i); + + prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw); + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + duk__enc_key_autoquote(js_ctx, k); + DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE); + } else { + duk__enc_key_autoquote(js_ctx, k); + DUK__EMIT_1(js_ctx, DUK_ASC_COLON); + } + + if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) { + DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon")); + DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size); + } else { + DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); + emitted = 1; + } + } + + /* If any non-Array value had enumerable virtual own + * properties, they should be serialized here. Standard + * types don't. + */ + + if (emitted) { + DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); + DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1); + } + } + DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); + } else if (c_bit & c_array) { + duk_uint_fast32_t arr_len; + duk_uint_fast32_t asize; + + DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET); + + /* Assume arrays are dense in the fast path. */ + if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) { + DUK_DD(DUK_DDPRINT("Array object is sparse, abort fast path")); + goto abort_fastpath; + } + + arr_len = (duk_uint_fast32_t) duk_hobject_get_length(js_ctx->thr, obj); + asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj); + if (arr_len > asize) { + /* Array length is larger than 'asize'. This shouldn't + * happen in practice. Bail out just in case. + */ + DUK_DD(DUK_DDPRINT("arr_len > asize, abort fast path")); + goto abort_fastpath; + } + /* Array part may be larger than 'length'; if so, iterate + * only up to array 'length'. + */ + for (i = 0; i < arr_len; i++) { + DUK_ASSERT(i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj)); + + tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i); + + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + } + + if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_val))) { + /* Gap in array; check for inherited property, + * bail out if one exists. This should be enough + * to support gappy arrays for all practical code. + */ + duk_hstring *h_tmp; + duk_bool_t has_inherited; + + /* XXX: refactor into an internal helper, pretty awkward */ + duk_push_uint((duk_context *) js_ctx->thr, (duk_uint_t) i); + h_tmp = duk_to_hstring((duk_context *) js_ctx->thr, -1); + DUK_ASSERT(h_tmp != NULL); + has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp); + duk_pop((duk_context *) js_ctx->thr); + + if (has_inherited) { + DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path")); + goto abort_fastpath; + } + + /* Ordinary gap, undefined encodes to 'null' in + * standard JSON (and no JX/JC support here now). + */ + DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path")); +#if defined(DUK_USE_JX) + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); +#else + DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); +#endif + } else { + if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) { + DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); + } + } + + DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); + emitted = 1; + } + + if (emitted) { + DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); + DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1); + } + } + DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET); + } else if (c_bit & c_unbox) { + /* Certain boxed types are required to go through + * automatic unboxing. Rely on internal value being + * sane (to avoid infinite recursion). + */ +#if 1 + /* The code below is incorrect if .toString() or .valueOf() have + * have been overridden. The correct approach would be to look up + * the method(s) and if they resolve to the built-in function we + * can safely bypass it and look up the internal value directly. + * Unimplemented for now, abort fast path for boxed values. + */ + goto abort_fastpath; +#else /* disabled */ + /* Disabled until fixed, see above. */ + duk_tval *tv_internal; + + DUK_DD(DUK_DDPRINT("auto unboxing in fast path")); + + tv_internal = duk_hobject_get_internal_value_tval_ptr(js_ctx->thr->heap, obj); + DUK_ASSERT(tv_internal != NULL); + DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) || + DUK_TVAL_IS_NUMBER(tv_internal) || + DUK_TVAL_IS_BOOLEAN(tv_internal) || + DUK_TVAL_IS_POINTER(tv_internal)); + + tv = tv_internal; + DUK_ASSERT(js_ctx->recursion_depth > 0); + js_ctx->recursion_depth--; /* required to keep recursion depth correct */ + goto restart_match; +#endif /* disabled */ +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + } else if (c_bit & c_func) { + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); + } else if (c_bit & c_bufobj) { + duk__enc_bufferobject(js_ctx, (duk_hbufferobject *) obj); +#endif + } else { + DUK_ASSERT((c_bit & c_undef) != 0); + + /* Must decrease recursion depth before returning. */ + DUK_ASSERT(js_ctx->recursion_depth > 0); + DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); + js_ctx->recursion_depth--; + goto emit_undefined; + } + + DUK_ASSERT(js_ctx->recursion_depth > 0); + DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); + js_ctx->recursion_depth--; + break; + } + case DUK_TAG_BUFFER: { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom_or_compatible) { + duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + break; + } else { + goto emit_undefined; + } +#else + goto emit_undefined; +#endif + } + case DUK_TAG_POINTER: { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom_or_compatible) { + duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv)); + break; + } else { + goto emit_undefined; + } +#else + goto emit_undefined; +#endif + } + case DUK_TAG_LIGHTFUNC: { + /* A lightfunc might also inherit a .toJSON() so just bail out. */ + /* XXX: Could just lookup .toJSON() and continue in fast path, + * as it would almost never be defined. + */ + DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path")); + goto abort_fastpath; + } +#if defined(DUK_USE_FASTINT) + case DUK_TAG_FASTINT: { + /* Number serialization has a significant impact relative to + * other fast path code, so careful fast path for fastints. + */ + duk__enc_fastint_tval(js_ctx, tv); + break; + } +#endif + default: { + /* XXX: A fast path for usual integers would be useful when + * fastint support is not enabled. + */ + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + + /* XXX: Stack discipline is annoying, could be changed in numconv. */ + duk_push_tval((duk_context *) js_ctx->thr, tv); + duk__enc_double(js_ctx); + duk_pop((duk_context *) js_ctx->thr); + +#if 0 + /* Could also rely on native sprintf(), but it will handle + * values like NaN, Infinity, -0, exponent notation etc in + * a JSON-incompatible way. + */ + duk_double_t d; + char buf[64]; + + DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); + d = DUK_TVAL_GET_DOUBLE(tv); + DUK_SPRINTF(buf, "%lg", d); + DUK__EMIT_CSTR(js_ctx, buf); +#endif + } + } + return 1; /* not undefined */ + + emit_undefined: + return 0; /* value was undefined/unsupported */ + + abort_fastpath: + /* Error message doesn't matter: the error is ignored anyway. */ + DUK_DD(DUK_DDPRINT("aborting fast path")); + DUK_ERROR_INTERNAL_DEFMSG(js_ctx->thr); + return 0; /* unreachable */ +} + +DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx) { + duk_json_enc_ctx *js_ctx; + duk_tval *tv; + + DUK_ASSERT(ctx != NULL); + tv = DUK_GET_TVAL_NEGIDX(ctx, -2); + DUK_ASSERT(DUK_TVAL_IS_POINTER(tv)); + js_ctx = (duk_json_enc_ctx *) DUK_TVAL_GET_POINTER(tv); + DUK_ASSERT(js_ctx != NULL); + + tv = DUK_GET_TVAL_NEGIDX(ctx, -1); + if (duk__json_stringify_fast_value(js_ctx, tv) == 0) { + DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path")); + return DUK_RET_ERROR; /* error message doesn't matter, ignored anyway */ + } + + return 0; +} +#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ + +/* + * Top level wrappers + */ + +DUK_INTERNAL +void duk_bi_json_parse_helper(duk_context *ctx, + duk_idx_t idx_value, + duk_idx_t idx_reviver, + duk_small_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_json_dec_ctx js_ctx_alloc; + duk_json_dec_ctx *js_ctx = &js_ctx_alloc; + duk_hstring *h_text; +#ifdef DUK_USE_ASSERTIONS + duk_idx_t entry_top = duk_get_top(ctx); +#endif + + /* negative top-relative indices not allowed now */ + DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0); + DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0); + + DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld", + (duk_tval *) duk_get_tval(ctx, idx_value), + (duk_tval *) duk_get_tval(ctx, idx_reviver), + (unsigned long) flags, + (long) duk_get_top(ctx))); + + DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc)); + js_ctx->thr = thr; +#ifdef DUK_USE_EXPLICIT_NULL_INIT + /* nothing now */ +#endif + js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT; + DUK_ASSERT(js_ctx->recursion_depth == 0); + + /* Flag handling currently assumes that flags are consistent. This is OK + * because the call sites are now strictly controlled. + */ + + js_ctx->flags = flags; +#if defined(DUK_USE_JX) + js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM; +#endif +#if defined(DUK_USE_JC) + js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE; +#endif +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE); +#endif + + h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place */ + DUK_ASSERT(h_text != NULL); + + /* JSON parsing code is allowed to read [p_start,p_end]: p_end is + * valid and points to the string NUL terminator (which is always + * guaranteed for duk_hstrings. + */ + js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text); + js_ctx->p = js_ctx->p_start; + js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) + + DUK_HSTRING_GET_BYTELEN(h_text); + DUK_ASSERT(*(js_ctx->p_end) == 0x00); + + duk__dec_value(js_ctx); /* -> [ ... value ] */ + + /* Trailing whitespace has been eaten by duk__dec_value(), so if + * we're not at end of input here, it's a SyntaxError. + */ + + if (js_ctx->p != js_ctx->p_end) { + duk__dec_syntax_error(js_ctx); + } + + if (duk_is_callable(ctx, idx_reviver)) { + DUK_DDD(DUK_DDDPRINT("applying reviver: %!T", + (duk_tval *) duk_get_tval(ctx, idx_reviver))); + + js_ctx->idx_reviver = idx_reviver; + + duk_push_object(ctx); + duk_dup(ctx, -2); /* -> [ ... val root val ] */ + duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */ + duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */ + + DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T", + (duk_tval *) duk_get_tval(ctx, -2), + (duk_tval *) duk_get_tval(ctx, -1))); + + duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */ + duk_remove(ctx, -2); /* -> [ ... val' ] */ + } else { + DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T", + (duk_tval *) duk_get_tval(ctx, idx_reviver))); + } + + /* Final result is at stack top. */ + + DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld", + (duk_tval *) duk_get_tval(ctx, idx_value), + (duk_tval *) duk_get_tval(ctx, idx_reviver), + (unsigned long) flags, + (duk_tval *) duk_get_tval(ctx, -1), + (long) duk_get_top(ctx))); + + DUK_ASSERT(duk_get_top(ctx) == entry_top + 1); +} + +DUK_INTERNAL +void duk_bi_json_stringify_helper(duk_context *ctx, + duk_idx_t idx_value, + duk_idx_t idx_replacer, + duk_idx_t idx_space, + duk_small_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_json_enc_ctx js_ctx_alloc; + duk_json_enc_ctx *js_ctx = &js_ctx_alloc; + duk_hobject *h; + duk_idx_t idx_holder; + duk_idx_t entry_top; + + /* negative top-relative indices not allowed now */ + DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0); + DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0); + DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0); + + DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld", + (duk_tval *) duk_get_tval(ctx, idx_value), + (duk_tval *) duk_get_tval(ctx, idx_replacer), + (duk_tval *) duk_get_tval(ctx, idx_space), + (unsigned long) flags, + (long) duk_get_top(ctx))); + + entry_top = duk_get_top(ctx); + + /* + * Context init + */ + + DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc)); + js_ctx->thr = thr; +#ifdef DUK_USE_EXPLICIT_NULL_INIT + js_ctx->h_replacer = NULL; + js_ctx->h_gap = NULL; +#endif + js_ctx->idx_proplist = -1; + + /* Flag handling currently assumes that flags are consistent. This is OK + * because the call sites are now strictly controlled. + */ + + js_ctx->flags = flags; + js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY; + js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES; +#ifdef DUK_USE_JX + js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM; +#endif +#ifdef DUK_USE_JC + js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE; +#endif +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE); +#endif + + /* The #ifdef clutter here handles the JX/JC enable/disable + * combinations properly. + */ +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL; /* standard JSON; array gaps */ +#if defined(DUK_USE_JX) + if (flags & DUK_JSON_FLAG_EXT_CUSTOM) { + js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED; + js_ctx->stridx_custom_nan = DUK_STRIDX_NAN; + js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY; + js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY; + js_ctx->stridx_custom_function = + (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ? + DUK_STRIDX_JSON_EXT_FUNCTION2 : + DUK_STRIDX_JSON_EXT_FUNCTION1; + } +#endif /* DUK_USE_JX */ +#if defined(DUK_USE_JX) && defined(DUK_USE_JC) + else +#endif /* DUK_USE_JX && DUK_USE_JC */ +#if defined(DUK_USE_JC) + if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) { + js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED; + js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN; + js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF; + js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF; + js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1; + } +#endif /* DUK_USE_JC */ +#endif /* DUK_USE_JX || DUK_USE_JC */ + +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | + DUK_JSON_FLAG_EXT_COMPATIBLE)) { + DUK_ASSERT(js_ctx->mask_for_undefined == 0); /* already zero */ + } + else +#endif /* DUK_USE_JX || DUK_USE_JC */ + { + js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED | + DUK_TYPE_MASK_POINTER | + DUK_TYPE_MASK_BUFFER | + DUK_TYPE_MASK_LIGHTFUNC; + } + + DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE); + + js_ctx->idx_loop = duk_push_object_internal(ctx); + DUK_ASSERT(js_ctx->idx_loop >= 0); + + /* [ ... buf loop ] */ + + /* + * Process replacer/proplist (2nd argument to JSON.stringify) + */ + + h = duk_get_hobject(ctx, idx_replacer); + if (h != NULL) { + if (DUK_HOBJECT_IS_CALLABLE(h)) { + js_ctx->h_replacer = h; + } else if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) { + /* Here the specification requires correct array index enumeration + * which is a bit tricky for sparse arrays (it is handled by the + * enum setup code). We now enumerate ancestors too, although the + * specification is not very clear on whether that is required. + */ + + duk_uarridx_t plist_idx = 0; + duk_small_uint_t enum_flags; + + js_ctx->idx_proplist = duk_push_array(ctx); /* XXX: array internal? */ + + enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY | + DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */ + duk_enum(ctx, idx_replacer, enum_flags); + while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) { + /* [ ... proplist enum_obj key val ] */ + if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) { + /* XXX: duplicates should be eliminated here */ + DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept", + (duk_tval *) duk_get_tval(ctx, -2), + (duk_tval *) duk_get_tval(ctx, -1))); + duk_to_string(ctx, -1); /* extra coercion of strings is OK */ + duk_put_prop_index(ctx, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */ + plist_idx++; + duk_pop(ctx); + } else { + DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject", + (duk_tval *) duk_get_tval(ctx, -2), + (duk_tval *) duk_get_tval(ctx, -1))); + duk_pop_2(ctx); + } + } + duk_pop(ctx); /* pop enum */ + + /* [ ... proplist ] */ + } + } + + /* [ ... buf loop (proplist) ] */ + + /* + * Process space (3rd argument to JSON.stringify) + */ + + h = duk_get_hobject(ctx, idx_space); + if (h != NULL) { + int c = DUK_HOBJECT_GET_CLASS_NUMBER(h); + if (c == DUK_HOBJECT_CLASS_NUMBER) { + duk_to_number(ctx, idx_space); + } else if (c == DUK_HOBJECT_CLASS_STRING) { + duk_to_string(ctx, idx_space); + } + } + + if (duk_is_number(ctx, idx_space)) { + duk_small_int_t nspace; + /* spaces[] must be static to allow initializer with old compilers like BCC */ + static const char spaces[10] = { + DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, + DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, + DUK_ASC_SPACE, DUK_ASC_SPACE + }; /* XXX: helper */ + + /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */ + nspace = (duk_small_int_t) duk_to_int_clamped(ctx, idx_space, 0 /*minval*/, 10 /*maxval*/); + DUK_ASSERT(nspace >= 0 && nspace <= 10); + + duk_push_lstring(ctx, spaces, (duk_size_t) nspace); + js_ctx->h_gap = duk_get_hstring(ctx, -1); + DUK_ASSERT(js_ctx->h_gap != NULL); + } else if (duk_is_string(ctx, idx_space)) { + /* XXX: substring in-place at idx_place? */ + duk_dup(ctx, idx_space); + duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */ + js_ctx->h_gap = duk_get_hstring(ctx, -1); + DUK_ASSERT(js_ctx->h_gap != NULL); + } else { + /* nop */ + } + + if (js_ctx->h_gap != NULL) { + /* if gap is empty, behave as if not given at all */ + if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) { + js_ctx->h_gap = NULL; + } + } + + /* [ ... buf loop (proplist) (gap) ] */ + + /* + * Fast path: assume no mutation, iterate object property tables + * directly; bail out if that assumption doesn't hold. + */ + +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) + if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */ + js_ctx->idx_proplist == -1) { /* proplist is very rare */ + duk_int_t pcall_rc; +#ifdef DUK_USE_MARK_AND_SWEEP + duk_small_uint_t prev_mark_and_sweep_base_flags; +#endif + + DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path")); + + /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[] + * array so we don't need two counter checks in the fast path. The + * slow path has a much larger recursion limit which we'll use if + * necessary. + */ + DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY); + js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY; + DUK_ASSERT(js_ctx->recursion_depth == 0); + + /* Execute the fast path in a protected call. If any error is thrown, + * fall back to the slow path. This includes e.g. recursion limit + * because the fast path has a smaller recursion limit (and simpler, + * limited loop detection). + */ + + duk_push_pointer(ctx, (void *) js_ctx); + duk_dup(ctx, idx_value); + +#if defined(DUK_USE_MARK_AND_SWEEP) + /* Must prevent finalizers which may have arbitrary side effects. */ + prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; + thr->heap->mark_and_sweep_base_flags |= + DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ + DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */ +#endif + + pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, 2 /*nargs*/, 0 /*nret*/); + +#if defined(DUK_USE_MARK_AND_SWEEP) + thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; +#endif + if (pcall_rc == DUK_EXEC_SUCCESS) { + DUK_DD(DUK_DDPRINT("fast path successful")); + DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw); + goto replace_finished; + } + + /* We come here for actual aborts (like encountering .toJSON()) + * but also for recursion/loop errors. Bufwriter size can be + * kept because we'll probably need at least as much as we've + * allocated so far. + */ + DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead")); + DUK_BW_RESET_SIZE(thr, &js_ctx->bw); + js_ctx->recursion_depth = 0; + } +#endif + + /* + * Create wrapper object and serialize + */ + + idx_holder = duk_push_object(ctx); + duk_dup(ctx, idx_value); + duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); + + DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, " + "proplist=%!T, gap=%!O, holder=%!T", + (unsigned long) js_ctx->flags, + (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop), + (duk_heaphdr *) js_ctx->h_replacer, + (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL), + (duk_heaphdr *) js_ctx->h_gap, + (duk_tval *) duk_get_tval(ctx, -1))); + + /* serialize the wrapper with empty string key */ + + duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); + + /* [ ... buf loop (proplist) (gap) holder "" ] */ + + js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT; + DUK_ASSERT(js_ctx->recursion_depth == 0); + + if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */ + /* Result is undefined. */ + duk_push_undefined(ctx); + } else { + /* Convert buffer to result string. */ + DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw); + } + + DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, " + "proplist=%!T, gap=%!O, holder=%!T", + (unsigned long) js_ctx->flags, + (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop), + (duk_heaphdr *) js_ctx->h_replacer, + (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL), + (duk_heaphdr *) js_ctx->h_gap, + (duk_tval *) duk_get_tval(ctx, idx_holder))); + + /* The stack has a variable shape here, so force it to the + * desired one explicitly. + */ + +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) + replace_finished: +#endif + duk_replace(ctx, entry_top); + duk_set_top(ctx, entry_top + 1); + + DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, " + "flags=0x%08lx, result=%!T, stack_top=%ld", + (duk_tval *) duk_get_tval(ctx, idx_value), + (duk_tval *) duk_get_tval(ctx, idx_replacer), + (duk_tval *) duk_get_tval(ctx, idx_space), + (unsigned long) flags, + (duk_tval *) duk_get_tval(ctx, -1), + (long) duk_get_top(ctx))); + + DUK_ASSERT(duk_get_top(ctx) == entry_top + 1); +} + +/* + * Entry points + */ + +DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_context *ctx) { + duk_bi_json_parse_helper(ctx, + 0 /*idx_value*/, + 1 /*idx_replacer*/, + 0 /*flags*/); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) { + duk_bi_json_stringify_helper(ctx, + 0 /*idx_value*/, + 1 /*idx_replacer*/, + 2 /*idx_space*/, + 0 /*flags*/); + return 1; +} + +#undef DUK__JSON_DECSTR_BUFSIZE +#undef DUK__JSON_DECSTR_CHUNKSIZE +#undef DUK__JSON_ENCSTR_CHUNKSIZE +#undef DUK__JSON_STRINGIFY_BUFSIZE +#undef DUK__JSON_MAX_ESC_LEN +/* + * Logging support + */ + +/* include removed: duk_internal.h */ + +/* 3-letter log level strings */ +DUK_LOCAL const duk_uint8_t duk__log_level_strings[] = { + (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_C, + (duk_uint8_t) DUK_ASC_UC_D, (duk_uint8_t) DUK_ASC_UC_B, (duk_uint8_t) DUK_ASC_UC_G, + (duk_uint8_t) DUK_ASC_UC_I, (duk_uint8_t) DUK_ASC_UC_N, (duk_uint8_t) DUK_ASC_UC_F, + (duk_uint8_t) DUK_ASC_UC_W, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_N, + (duk_uint8_t) DUK_ASC_UC_E, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_R, + (duk_uint8_t) DUK_ASC_UC_F, (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_L +}; + +/* Constructor */ +DUK_INTERNAL duk_ret_t duk_bi_logger_constructor(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t nargs; + + /* Calling as a non-constructor is not meaningful. */ + if (!duk_is_constructor_call(ctx)) { + return DUK_RET_TYPE_ERROR; + } + + nargs = duk_get_top(ctx); + duk_set_top(ctx, 1); + + duk_push_this(ctx); + + /* [ name this ] */ + + if (nargs == 0) { + /* Automatic defaulting of logger name from caller. This would + * work poorly with tail calls, but constructor calls are currently + * never tail calls, so tail calls are not an issue now. + */ + + if (thr->callstack_top >= 2) { + duk_activation *act_caller = thr->callstack + thr->callstack_top - 2; + duk_hobject *func_caller; + + func_caller = DUK_ACT_GET_FUNC(act_caller); + if (func_caller) { + /* Stripping the filename might be a good idea + * ("/foo/bar/quux.js" -> logger name "quux"), + * but now used verbatim. + */ + duk_push_hobject(ctx, func_caller); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME); + duk_replace(ctx, 0); + } + } + } + /* the stack is unbalanced here on purpose; we only rely on the + * initial two values: [ name this ]. + */ + + if (duk_is_string(ctx, 0)) { + duk_dup(ctx, 0); + duk_put_prop_stridx(ctx, 1, DUK_STRIDX_LC_N); + } else { + /* don't set 'n' at all, inherited value is used as name */ + } + + duk_compact(ctx, 1); + + return 0; /* keep default instance */ +} + +/* Default function to format objects. Tries to use toLogString() but falls + * back to toString(). Any errors are propagated out without catching. + */ +DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx) { + if (duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_LOG_STRING)) { + /* [ arg toLogString ] */ + + duk_dup(ctx, 0); + duk_call_method(ctx, 0); + + /* [ arg result ] */ + return 1; + } + + /* [ arg undefined ] */ + duk_pop(ctx); + duk_to_string(ctx, 0); + return 1; +} + +/* Default function to write a formatted log line. Writes to stderr, + * appending a newline to the log line. + * + * The argument is a buffer whose visible size contains the log message. + * This function should avoid coercing the buffer to a string to avoid + * string table traffic. + */ +DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx) { + const char *data; + duk_size_t data_len; + + DUK_UNREF(ctx); + DUK_UNREF(data); + DUK_UNREF(data_len); + +#ifdef DUK_USE_FILE_IO + data = (const char *) duk_require_buffer(ctx, 0, &data_len); + DUK_FWRITE((const void *) data, 1, data_len, DUK_STDERR); + DUK_FPUTC((int) '\n', DUK_STDERR); + DUK_FFLUSH(DUK_STDERR); +#else + /* nop */ +#endif + return 0; +} + +/* Log frontend shared helper, magic value indicates log level. Provides + * frontend functions: trace(), debug(), info(), warn(), error(), fatal(). + * This needs to have small footprint, reasonable performance, minimal + * memory churn, etc. + */ +DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_double_t now; + duk_small_int_t entry_lev = duk_get_current_magic(ctx); + duk_small_int_t logger_lev; + duk_int_t nargs; + duk_int_t i; + duk_size_t tot_len; + const duk_uint8_t *arg_str; + duk_size_t arg_len; + duk_uint8_t *buf, *p; + const duk_uint8_t *q; + duk_uint8_t date_buf[DUK_BI_DATE_ISO8601_BUFSIZE]; + duk_size_t date_len; + duk_small_int_t rc; + + DUK_ASSERT(entry_lev >= 0 && entry_lev <= 5); + DUK_UNREF(thr); + + /* XXX: sanitize to printable (and maybe ASCII) */ + /* XXX: better multiline */ + + /* + * Logger arguments are: + * + * magic: log level (0-5) + * this: logger + * stack: plain log args + * + * We want to minimize memory churn so a two-pass approach + * is used: first pass formats arguments and computes final + * string length, second pass copies strings either into a + * pre-allocated and reused buffer (short messages) or into a + * newly allocated fixed buffer. If the backend function plays + * nice, it won't coerce the buffer to a string (and thus + * intern it). + */ + + nargs = duk_get_top(ctx); + + /* [ arg1 ... argN this ] */ + + /* + * Log level check + */ + + duk_push_this(ctx); + + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_L); + logger_lev = (duk_small_int_t) duk_get_int(ctx, -1); + if (entry_lev < logger_lev) { + return 0; + } + /* log level could be popped but that's not necessary */ + + now = DUK_USE_DATE_GET_NOW(ctx); + duk_bi_date_format_timeval(now, date_buf); + date_len = DUK_STRLEN((const char *) date_buf); + + duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LC_N); + duk_to_string(ctx, -1); + DUK_ASSERT(duk_is_string(ctx, -1)); + + /* [ arg1 ... argN this loggerLevel loggerName ] */ + + /* + * Pass 1 + */ + + /* Line format: