summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMicah Anderson <micah@leap.se>2014-01-15 18:14:23 +0000
committerMicah Anderson <micah@riseup.net>2014-01-17 15:53:14 -0500
commit07cc4e305e806a7bb236fbb8f6d9893a2011d85e (patch)
tree1bb9456f1beef19a916878d154966da825554cd5
parent65a973d6304de0098ad47c2df517a48f45ebe68a (diff)
initial debianization
-rw-r--r--debian/README.Debian6
-rw-r--r--debian/README.build10
-rw-r--r--debian/bigcouch.lintian-overrides1
-rw-r--r--debian/bigcouch.postinst26
-rw-r--r--debian/bigcouch.postrm24
-rw-r--r--debian/bigcouch.prerm12
-rw-r--r--debian/changelog36
-rw-r--r--debian/compat1
-rw-r--r--debian/control16
-rw-r--r--debian/copyright47
-rw-r--r--debian/docs1
-rw-r--r--debian/etc/sv/bigcouch/log/run2
-rw-r--r--debian/etc/sv/bigcouch/run4
-rw-r--r--debian/patches/bigcouch-configuration-changes2950
-rw-r--r--debian/patches/disable_embedded_rebar82
-rw-r--r--debian/patches/disable_embedded_scons20
-rw-r--r--debian/patches/fix-body_too_large-error16
-rw-r--r--debian/patches/remove_external_dependencies32
-rw-r--r--debian/patches/series7
-rw-r--r--debian/patches/support-destdir.patch25
-rw-r--r--debian/patches/update-pthread-linking-flags27
-rwxr-xr-xdebian/rules19
-rw-r--r--debian/source/format1
23 files changed, 3365 insertions, 0 deletions
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644
index 00000000..28e0e728
--- /dev/null
+++ b/debian/README.Debian
@@ -0,0 +1,6 @@
+bigcouch for Debian
+-------------------
+
+First package attempt using standard tools.
+
+ -- Robert Newson <robert.newson@cloudant.com> Tue, 05 Apr 2011 20:53:35 +0100
diff --git a/debian/README.build b/debian/README.build
new file mode 100644
index 00000000..b928e380
--- /dev/null
+++ b/debian/README.build
@@ -0,0 +1,10 @@
+To build this package you will need to create ../bigcouch-$VERSION.tar.gz as follows
+
+1) git clone git://github.com/cloudant/bigcouch.git
+2) git archive --format=tar bigcouch-$VERSION | gzip > bigcouch_$VERSION.orig.tar.gz
+3) move that file to the directory above this one.
+4) untar that file into *this* directory.
+
+Now build the package;
+
+4) debuild -us -uc
diff --git a/debian/bigcouch.lintian-overrides b/debian/bigcouch.lintian-overrides
new file mode 100644
index 00000000..9473130b
--- /dev/null
+++ b/debian/bigcouch.lintian-overrides
@@ -0,0 +1 @@
+bigcouch: dir-or-file-in-opt
diff --git a/debian/bigcouch.postinst b/debian/bigcouch.postinst
new file mode 100644
index 00000000..59f9d86e
--- /dev/null
+++ b/debian/bigcouch.postinst
@@ -0,0 +1,26 @@
+#!/bin/sh -e
+
+case $1 in
+ configure)
+ if ! getent passwd bigcouch > /dev/null; then
+ adduser --system --quiet --home /home/bigcouch \
+ --shell /bin/bash --group bigcouch
+ fi
+ if test "`id -u bigcouch`" -eq 0; then
+ echo "The bigcouch administrative user must not be root." >&2
+ false
+ fi
+ if test "`id -g bigcouch`" -eq 0; then
+ echo "The bigcouch administrative group must not be root." >&2
+ false
+ fi
+ chown -R bigcouch:bigcouch /opt/bigcouch
+ mkdir -p /home/bigcouch
+ chown -R bigcouch:bigcouch /home/bigcouch
+ chown -R bigcouch:bigcouch /opt/bigcouch
+ chown -R root:root /etc/sv/bigcouch
+ ln -sf /etc/sv/bigcouch /etc/service/
+ ;;
+esac
+
+#DEBHELPER#
diff --git a/debian/bigcouch.postrm b/debian/bigcouch.postrm
new file mode 100644
index 00000000..7b0e651a
--- /dev/null
+++ b/debian/bigcouch.postrm
@@ -0,0 +1,24 @@
+#!/bin/sh -e
+
+case $1 in
+ purge)
+ if test -d "/etc/sv/bigcouch"; then
+ rm -r -f "/etc/sv/bigcouch"
+ fi
+ if test -d "/opt/bigcouch"; then
+ rm -r -f "/opt/bigcouch"
+ fi
+ if getent passwd bigcouch > /dev/null && which deluser > /dev/null; then
+ for PID in `ps --no-headers -u bigcouch -opid`
+ do
+ kill $PID
+ done
+ deluser bigcouch
+ fi
+ if getent group bigcouch > /dev/null && which delgroup > /dev/null; then
+ delgroup bigcouch
+ fi
+ ;;
+esac
+
+#DEBHELPER#
diff --git a/debian/bigcouch.prerm b/debian/bigcouch.prerm
new file mode 100644
index 00000000..bcb054da
--- /dev/null
+++ b/debian/bigcouch.prerm
@@ -0,0 +1,12 @@
+#!/bin/sh -e
+
+case $1 in
+ remove)
+ if test -d "/etc/service/bigcouch"; then
+ sv down bigcouch
+ rm -r -f /etc/service/bigcouch
+ fi
+ ;;
+esac
+
+#DEBHELPER#
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 00000000..a119cd7d
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,36 @@
+bigcouch (0.4.2-0.1) UNRELEASED; urgency=low
+
+ * replace embedded rebar with Build-dependency on backported version
+ * add remove_external_dependencies patch to stop pulling the
+ dependencies via git
+ * embed the dependencies that were previously pulled in via git from
+ rebar.config
+ * refreshed the support-destdir patch
+ * add fix-body_too_large-error patch to fix problem with POSTing large
+ data to update handlers
+ * add update-pthread-linking-flags patch to fix pthread linking
+ * add disable_embedded_scons patch
+ * add scons to Build-dependencies
+ * add patch to hardcode version instead of invoking git
+ * add patch to add configuration files that are generated by building
+ process and should be present in the tarball
+
+ -- Micah Anderson <micah@leap.se> Wed, 15 Jan 2014 17:30:31 +0000
+
+bigcouch (0.4.2-1) unstable; urgency=low
+
+ * Updated build for 0.4.2
+
+ -- Robert Newson <robert.newson@cloudant.com> Fri, 15 Feb 2013 18:02:32 +0000
+
+bigcouch (0.4.0-1) unstable; urgency=low
+
+ * Updated build for 0.4.0
+
+ -- Paul Davis <paul@cloudant.com> Tue, 01 Nov 2011 16:17:18 +0600
+
+bigcouch (0.3.1-1) unstable; urgency=low
+
+ * Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP>
+
+ -- Robert Newson <robert.newson@cloudant.com> Tue, 05 Apr 2011 20:53:35 +0100
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 00000000..7f8f011e
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/debian/control b/debian/control
new file mode 100644
index 00000000..3c25dd62
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,16 @@
+Source: bigcouch
+Section: misc
+Priority: extra
+Maintainer: Cloudant Support <support@cloudant.com>
+Build-Depends: debhelper, quilt, autotools-dev, libmozjs185-dev, libicu-dev, git | git-core, python, libcurl4-openssl-dev, erlang-dev, erlang-crypto, erlang-inets, erlang-xmerl, erlang-eunit, erlang-os-mon, erlang-ssl, erlang-syntax-tools, erlang-tools, erlang-reltool, rebar, scons
+Standards-Version: 3.8.4
+Homepage: http://cloudant.com/
+Vcs-Git: git://github.com/cloudant/bigcouch.git
+Vcs-Browser: http://github.com/cloudant/bigcouch
+
+Package: bigcouch
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, libmozjs185-1.0, runit
+Conflicts: couchdb
+Description: BigCouch is a dynamo-style implementation of Apache CouchDB
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 00000000..d5453d10
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,47 @@
+This work was packaged for Debian by:
+
+ Robert Newson <robert.newson@cloudant.com> on Tue, 05 Apr 2011 20:53:35 +0100
+
+It was downloaded from http://cloudant.com
+
+Copyright:
+
+ Copyright Cloudant
+
+License:
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+On Debian systems, the complete text of the Apache version 2.0 license
+can be found in `/usr/share/common-licenses/Apache-2.0'.
+
+The Debian packaging is:
+
+ Copyright (C) 2011 Robert Newson <robert.newson@cloudant.com>
+
+License:
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+On Debian systems, the complete text of the Apache version 2.0 license
+can be found in `/usr/share/common-licenses/Apache-2.0'.
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 00000000..b43bf86b
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1 @@
+README.md
diff --git a/debian/etc/sv/bigcouch/log/run b/debian/etc/sv/bigcouch/log/run
new file mode 100644
index 00000000..3195b018
--- /dev/null
+++ b/debian/etc/sv/bigcouch/log/run
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec chpst svlogd -tt ./main
diff --git a/debian/etc/sv/bigcouch/run b/debian/etc/sv/bigcouch/run
new file mode 100644
index 00000000..875c3f02
--- /dev/null
+++ b/debian/etc/sv/bigcouch/run
@@ -0,0 +1,4 @@
+#!/bin/bash
+exec 2>&1
+export HOME=/home/bigcouch
+exec chpst -u bigcouch /opt/bigcouch/bin/bigcouch
diff --git a/debian/patches/bigcouch-configuration-changes b/debian/patches/bigcouch-configuration-changes
new file mode 100644
index 00000000..0862ca6b
--- /dev/null
+++ b/debian/patches/bigcouch-configuration-changes
@@ -0,0 +1,2950 @@
+Description: building bigcouch generates a bunch of configuration files
+ When building bigcouch, a handful of configuration files are generated
+ that normally would have been generated upstream before releasing into
+ a tarball
+ .
+Author: Micah Anderson <micah@leap.se>
+
+---
+The information above should follow the Patch Tagging Guidelines, please
+checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
+are templates for supplementary fields that you might want to add:
+
+Origin: <vendor|upstream|other>, <url of original patch>
+Bug: <url in upstream bugtracker>
+Bug-Debian: http://bugs.debian.org/<bugnumber>
+Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
+Forwarded: <no|not-needed|url proving that it has been forwarded>
+Reviewed-By: <name and email of someone who approved the patch>
+Last-Update: <YYYY-MM-DD>
+
+Index: bigcouch-0.4.2.leap/install.mk
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/install.mk 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,5 @@
++# The contents of this file are auto-generated by configure
++prefix = /opt/bigcouch
++data_dir = /opt/bigcouch/var/lib
++view_dir = /opt/bigcouch/var/lib
++user = root
+Index: bigcouch-0.4.2.leap/couchjs/config.log
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/config.log 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,136 @@
++file /root/cloudant/bigcouch-0.4.2.leap/couchjs/build/SConscript,line 52:
++ Configure(confdir = .sconf_temp)
++scons: Configure: Checking for C library m...
++.sconf_temp/conftest_0.c <-
++ |
++ |
++ |
++ |int
++ |main() {
++ |
++ |return 0;
++ |}
++ |
++c++ -o .sconf_temp/conftest_0.o -c -g -O2 -DXP_UNIX .sconf_temp/conftest_0.c
++c++ -o .sconf_temp/conftest_0 -pthread .sconf_temp/conftest_0.o -lm
++scons: Configure: yes
++
++scons: Configure: Checking for C library pthread...
++.sconf_temp/conftest_1.c <-
++ |
++ |
++ |
++ |int
++ |main() {
++ |
++ |return 0;
++ |}
++ |
++c++ -o .sconf_temp/conftest_1.o -c -g -O2 -DXP_UNIX .sconf_temp/conftest_1.c
++c++ -o .sconf_temp/conftest_1 -pthread .sconf_temp/conftest_1.o -lm -lpthread
++scons: Configure: yes
++
++scons: Configure: Checking for C library nspr4...
++.sconf_temp/conftest_2.c <-
++ |
++ |
++ |
++ |int
++ |main() {
++ |
++ |return 0;
++ |}
++ |
++c++ -o .sconf_temp/conftest_2.o -c -g -O2 -DXP_UNIX .sconf_temp/conftest_2.c
++c++ -o .sconf_temp/conftest_2 -pthread .sconf_temp/conftest_2.o -lm -lpthread -lnspr4
++scons: Configure: yes
++
++scons: Configure: Checking for C header file mozjs/jsapi.h...
++.sconf_temp/conftest_3.c <-
++ |
++ |#include <mozjs/jsapi.h>
++ |
++ |
++c++ -o .sconf_temp/conftest_3.o -c -g -O2 -DXP_UNIX .sconf_temp/conftest_3.c
++.sconf_temp/conftest_3.c:2:25: fatal error: mozjs/jsapi.h: No such file or directory
++compilation terminated.
++scons: Configure: no
++
++scons: Configure: Checking for C header file js/jsapi.h...
++.sconf_temp/conftest_4.c <-
++ |
++ |#include <js/jsapi.h>
++ |
++ |
++c++ -o .sconf_temp/conftest_4.o -c -g -O2 -DXP_UNIX .sconf_temp/conftest_4.c
++scons: Configure: yes
++
++scons: Configure: Checking for C library mozjs185-1.0...
++.sconf_temp/conftest_5.c <-
++ |
++ |
++ |#include "js/jsapi.h"
++ |
++ |int
++ |main() {
++ |
++ |return 0;
++ |}
++ |
++c++ -o .sconf_temp/conftest_5.o -c -g -O2 -DXP_UNIX .sconf_temp/conftest_5.c
++c++ -o .sconf_temp/conftest_5 -pthread .sconf_temp/conftest_5.o -lm -lpthread -lnspr4 -lmozjs185-1.0
++scons: Configure: yes
++
++scons: Configure: Checking whether JS_NewCompartmentAndGlobalObject is declared...
++.sconf_temp/conftest_6.c <-
++ |#include <js/jsapi.h>
++ |int main()
++ |{
++ |#ifndef JS_NewCompartmentAndGlobalObject
++ | (void) JS_NewCompartmentAndGlobalObject;
++ |#endif
++ | ;
++ | return 0;
++ |}
++ |
++c++ -o .sconf_temp/conftest_6.o -c -g -O2 -DXP_UNIX .sconf_temp/conftest_6.c
++scons: Configure: yes
++
++scons: Configure: Checking for C type JSScript*...
++.sconf_temp/conftest_7.c <-
++ |
++ |
++ |#include "js/jsapi.h"
++ |
++ |int main() {
++ | if ((JSScript* *) 0)
++ | return 0;
++ | if (sizeof (JSScript*))
++ | return 0;
++ |}
++ |
++c++ -o .sconf_temp/conftest_7.o -c -g -O2 -DXP_UNIX .sconf_temp/conftest_7.c
++.sconf_temp/conftest_7.c: In function 'int main()':
++.sconf_temp/conftest_7.c:6:8: error: 'JSScript' was not declared in this scope
++.sconf_temp/conftest_7.c:6:19: error: expected primary-expression before ')' token
++.sconf_temp/conftest_7.c:6:21: error: expected ')' before numeric constant
++.sconf_temp/conftest_7.c:8:15: error: 'JSScript' was not declared in this scope
++.sconf_temp/conftest_7.c:8:24: error: expected primary-expression before ')' token
++scons: Configure: no
++
++scons: Configure: Checking for C library curl...
++.sconf_temp/conftest_8.c <-
++ |
++ |
++ |
++ |int
++ |main() {
++ |
++ |return 0;
++ |}
++ |
++c++ -o .sconf_temp/conftest_8.o -c -g -O2 -DXP_UNIX .sconf_temp/conftest_8.c
++c++ -o .sconf_temp/conftest_8 -pthread .sconf_temp/conftest_8.o -lm -lpthread -lnspr4 -lmozjs185-1.0 -lcurl
++scons: Configure: yes
++
++
+Index: bigcouch-0.4.2.leap/couchjs/build/http.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/http.c 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,638 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "config.h"
++#include "sm.h"
++#include "utf8.h"
++
++// Soft dependency on cURL bindings because they're
++// only used when running the JS tests from the
++// command line which is rare.
++#ifndef HAVE_LIBCURL
++
++void
++http_check_enabled()
++{
++ fprintf(stderr, "HTTP API was disabled at compile time.\n");
++ exit(3);
++}
++
++
++JSBool
++http_ctor(JSContext* cx, JSObject* req)
++{
++ return JS_FALSE;
++}
++
++
++JSBool
++http_dtor(JSContext* cx, JSObject* req)
++{
++ return JS_FALSE;
++}
++
++
++JSBool
++http_open(JSContext* cx, JSObject* req, jsval mth, jsval url, jsval snc)
++{
++ return JS_FALSE;
++}
++
++
++JSBool
++http_set_hdr(JSContext* cx, JSObject* req, jsval name, jsval val)
++{
++ return JS_FALSE;
++}
++
++
++JSBool
++http_send(JSContext* cx, JSObject* req, jsval body)
++{
++ return JS_FALSE;
++}
++
++
++int
++http_status(JSContext* cx, JSObject* req)
++{
++ return -1;
++}
++
++
++#else
++#include <curl/curl.h>
++
++
++void
++http_check_enabled()
++{
++ return;
++}
++
++
++// Map some of the string function names to things which exist on Windows
++#ifdef XP_WIN
++#define strcasecmp _strcmpi
++#define strncasecmp _strnicmp
++#define snprintf _snprintf
++#endif
++
++
++typedef struct curl_slist CurlHeaders;
++
++
++typedef struct {
++ int method;
++ char* url;
++ CurlHeaders* req_headers;
++ jsint last_status;
++} HTTPData;
++
++
++const char* METHODS[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "COPY", NULL};
++
++
++#define GET 0
++#define HEAD 1
++#define POST 2
++#define PUT 3
++#define DELETE 4
++#define COPY 5
++
++
++static JSBool
++go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t blen);
++
++
++static JSString*
++str_from_binary(JSContext* cx, char* data, size_t length);
++
++
++JSBool
++http_ctor(JSContext* cx, JSObject* req)
++{
++ HTTPData* http = NULL;
++ JSBool ret = JS_FALSE;
++
++ http = (HTTPData*) malloc(sizeof(HTTPData));
++ if(!http)
++ {
++ JS_ReportError(cx, "Failed to create CouchHTTP instance.");
++ goto error;
++ }
++
++ http->method = -1;
++ http->url = NULL;
++ http->req_headers = NULL;
++ http->last_status = -1;
++
++ if(!JS_SetPrivate(cx, req, http))
++ {
++ JS_ReportError(cx, "Failed to set private CouchHTTP data.");
++ goto error;
++ }
++
++ ret = JS_TRUE;
++ goto success;
++
++error:
++ if(http) free(http);
++
++success:
++ return ret;
++}
++
++
++void
++http_dtor(JSContext* cx, JSObject* obj)
++{
++ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
++ if(http) {
++ if(http->url) free(http->url);
++ if(http->req_headers) curl_slist_free_all(http->req_headers);
++ free(http);
++ }
++}
++
++
++JSBool
++http_open(JSContext* cx, JSObject* req, jsval mth, jsval url, jsval snc)
++{
++ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
++ char* method = NULL;
++ int methid;
++ JSBool ret = JS_FALSE;
++
++ if(!http) {
++ JS_ReportError(cx, "Invalid CouchHTTP instance.");
++ goto done;
++ }
++
++ if(JSVAL_IS_VOID(mth)) {
++ JS_ReportError(cx, "You must specify a method.");
++ goto done;
++ }
++
++ method = enc_string(cx, mth, NULL);
++ if(!method) {
++ JS_ReportError(cx, "Failed to encode method.");
++ goto done;
++ }
++
++ for(methid = 0; METHODS[methid] != NULL; methid++) {
++ if(strcasecmp(METHODS[methid], method) == 0) break;
++ }
++
++ if(methid > COPY) {
++ JS_ReportError(cx, "Invalid method specified.");
++ goto done;
++ }
++
++ http->method = methid;
++
++ if(JSVAL_IS_VOID(url)) {
++ JS_ReportError(cx, "You must specify a URL.");
++ goto done;
++ }
++
++ if(http->url != NULL) {
++ free(http->url);
++ http->url = NULL;
++ }
++
++ http->url = enc_string(cx, url, NULL);
++ if(http->url == NULL) {
++ JS_ReportError(cx, "Failed to encode URL.");
++ goto done;
++ }
++
++ if(JSVAL_IS_BOOLEAN(snc) && JSVAL_TO_BOOLEAN(snc)) {
++ JS_ReportError(cx, "Synchronous flag must be false.");
++ goto done;
++ }
++
++ if(http->req_headers) {
++ curl_slist_free_all(http->req_headers);
++ http->req_headers = NULL;
++ }
++
++ // Disable Expect: 100-continue
++ http->req_headers = curl_slist_append(http->req_headers, "Expect:");
++
++ ret = JS_TRUE;
++
++done:
++ if(method) free(method);
++ return ret;
++}
++
++
++JSBool
++http_set_hdr(JSContext* cx, JSObject* req, jsval name, jsval val)
++{
++ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
++ char* keystr = NULL;
++ char* valstr = NULL;
++ char* hdrbuf = NULL;
++ size_t hdrlen = -1;
++ JSBool ret = JS_FALSE;
++
++ if(!http) {
++ JS_ReportError(cx, "Invalid CouchHTTP instance.");
++ goto done;
++ }
++
++ if(JSVAL_IS_VOID(name))
++ {
++ JS_ReportError(cx, "You must speciy a header name.");
++ goto done;
++ }
++
++ keystr = enc_string(cx, name, NULL);
++ if(!keystr)
++ {
++ JS_ReportError(cx, "Failed to encode header name.");
++ goto done;
++ }
++
++ if(JSVAL_IS_VOID(val))
++ {
++ JS_ReportError(cx, "You must specify a header value.");
++ goto done;
++ }
++
++ valstr = enc_string(cx, val, NULL);
++ if(!valstr)
++ {
++ JS_ReportError(cx, "Failed to encode header value.");
++ goto done;
++ }
++
++ hdrlen = strlen(keystr) + strlen(valstr) + 3;
++ hdrbuf = (char*) malloc(hdrlen * sizeof(char));
++ if(!hdrbuf) {
++ JS_ReportError(cx, "Failed to allocate header buffer.");
++ goto done;
++ }
++
++ snprintf(hdrbuf, hdrlen, "%s: %s", keystr, valstr);
++ http->req_headers = curl_slist_append(http->req_headers, hdrbuf);
++
++ ret = JS_TRUE;
++
++done:
++ if(keystr) free(keystr);
++ if(valstr) free(valstr);
++ if(hdrbuf) free(hdrbuf);
++ return ret;
++}
++
++JSBool
++http_send(JSContext* cx, JSObject* req, jsval body)
++{
++ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
++ char* bodystr = NULL;
++ size_t bodylen = 0;
++ JSBool ret = JS_FALSE;
++
++ if(!http) {
++ JS_ReportError(cx, "Invalid CouchHTTP instance.");
++ goto done;
++ }
++
++ if(!JSVAL_IS_VOID(body)) {
++ bodystr = enc_string(cx, body, &bodylen);
++ if(!bodystr) {
++ JS_ReportError(cx, "Failed to encode body.");
++ goto done;
++ }
++ }
++
++ ret = go(cx, req, http, bodystr, bodylen);
++
++done:
++ if(bodystr) free(bodystr);
++ return ret;
++}
++
++int
++http_status(JSContext* cx, JSObject* req)
++{
++ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
++
++ if(!http) {
++ JS_ReportError(cx, "Invalid CouchHTTP instance.");
++ return JS_FALSE;
++ }
++
++ return http->last_status;
++}
++
++// Curl Helpers
++
++typedef struct {
++ HTTPData* http;
++ JSContext* cx;
++ JSObject* resp_headers;
++ char* sendbuf;
++ size_t sendlen;
++ size_t sent;
++ int sent_once;
++ char* recvbuf;
++ size_t recvlen;
++ size_t read;
++} CurlState;
++
++/*
++ * I really hate doing this but this doesn't have to be
++ * uber awesome, it just has to work.
++ */
++CURL* HTTP_HANDLE = NULL;
++char ERRBUF[CURL_ERROR_SIZE];
++
++static size_t send_body(void *ptr, size_t size, size_t nmem, void *data);
++static int seek_body(void *ptr, curl_off_t offset, int origin);
++static size_t recv_body(void *ptr, size_t size, size_t nmem, void *data);
++static size_t recv_header(void *ptr, size_t size, size_t nmem, void *data);
++
++static JSBool
++go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
++{
++ CurlState state;
++ JSString* jsbody;
++ JSBool ret = JS_FALSE;
++ jsval tmp;
++
++ state.cx = cx;
++ state.http = http;
++
++ state.sendbuf = body;
++ state.sendlen = bodylen;
++ state.sent = 0;
++ state.sent_once = 0;
++
++ state.recvbuf = NULL;
++ state.recvlen = 0;
++ state.read = 0;
++
++ if(HTTP_HANDLE == NULL) {
++ HTTP_HANDLE = curl_easy_init();
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_READFUNCTION, send_body);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_SEEKFUNCTION,
++ (curl_seek_callback) seek_body);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_HEADERFUNCTION, recv_header);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEFUNCTION, recv_body);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOPROGRESS, 1);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_ERRORBUFFER, ERRBUF);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_COOKIEFILE, "");
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_USERAGENT,
++ "CouchHTTP Client - Relax");
++ }
++
++ if(!HTTP_HANDLE) {
++ JS_ReportError(cx, "Failed to initialize cURL handle.");
++ goto done;
++ }
++
++ if(http->method < 0 || http->method > COPY) {
++ JS_ReportError(cx, "INTERNAL: Unknown method.");
++ goto done;
++ }
++
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_CUSTOMREQUEST, METHODS[http->method]);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOBODY, 0);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 1);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_UPLOAD, 0);
++
++ if(http->method == HEAD) {
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOBODY, 1);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 0);
++ } else if(http->method == POST || http->method == PUT) {
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_UPLOAD, 1);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 0);
++ }
++
++ if(body && bodylen) {
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, bodylen);
++ } else {
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, 0);
++ }
++
++ // curl_easy_setopt(HTTP_HANDLE, CURLOPT_VERBOSE, 1);
++
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_URL, http->url);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_HTTPHEADER, http->req_headers);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_READDATA, &state);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_SEEKDATA, &state);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEHEADER, &state);
++ curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEDATA, &state);
++
++ if(curl_easy_perform(HTTP_HANDLE) != 0) {
++ JS_ReportError(cx, "Failed to execute HTTP request: %s", ERRBUF);
++ goto done;
++ }
++
++ if(!state.resp_headers) {
++ JS_ReportError(cx, "Failed to recieve HTTP headers.");
++ goto done;
++ }
++
++ tmp = OBJECT_TO_JSVAL(state.resp_headers);
++ if(!JS_DefineProperty(
++ cx, obj,
++ "_headers",
++ tmp,
++ NULL, NULL,
++ JSPROP_READONLY
++ )) {
++ JS_ReportError(cx, "INTERNAL: Failed to set response headers.");
++ goto done;
++ }
++
++ if(state.recvbuf) {
++ state.recvbuf[state.read] = '\0';
++ jsbody = dec_string(cx, state.recvbuf, state.read+1);
++ if(!jsbody) {
++ // If we can't decode the body as UTF-8 we forcefully
++ // convert it to a string by just forcing each byte
++ // to a jschar.
++ jsbody = str_from_binary(cx, state.recvbuf, state.read);
++ if(!jsbody) {
++ if(!JS_IsExceptionPending(cx)) {
++ JS_ReportError(cx, "INTERNAL: Failed to decode body.");
++ }
++ goto done;
++ }
++ }
++ tmp = STRING_TO_JSVAL(jsbody);
++ } else {
++ tmp = JS_GetEmptyStringValue(cx);
++ }
++
++ if(!JS_DefineProperty(
++ cx, obj,
++ "responseText",
++ tmp,
++ NULL, NULL,
++ JSPROP_READONLY
++ )) {
++ JS_ReportError(cx, "INTERNAL: Failed to set responseText.");
++ goto done;
++ }
++
++ ret = JS_TRUE;
++
++done:
++ if(state.recvbuf) JS_free(cx, state.recvbuf);
++ return ret;
++}
++
++static size_t
++send_body(void *ptr, size_t size, size_t nmem, void *data)
++{
++ CurlState* state = (CurlState*) data;
++ size_t length = size * nmem;
++ size_t towrite = state->sendlen - state->sent;
++
++ // Assume this is cURL trying to resend a request that
++ // failed.
++ if(towrite == 0 && state->sent_once == 0) {
++ state->sent_once = 1;
++ return 0;
++ } else if(towrite == 0) {
++ state->sent = 0;
++ state->sent_once = 0;
++ towrite = state->sendlen;
++ }
++
++ if(length < towrite) towrite = length;
++
++ memcpy(ptr, state->sendbuf + state->sent, towrite);
++ state->sent += towrite;
++
++ return towrite;
++}
++
++static int
++seek_body(void* ptr, curl_off_t offset, int origin)
++{
++ CurlState* state = (CurlState*) ptr;
++ if(origin != SEEK_SET) return -1;
++
++ state->sent = (size_t) offset;
++ return (int) state->sent;
++}
++
++static size_t
++recv_header(void *ptr, size_t size, size_t nmem, void *data)
++{
++ CurlState* state = (CurlState*) data;
++ char code[4];
++ char* header = (char*) ptr;
++ size_t length = size * nmem;
++ JSString* hdr = NULL;
++ jsuint hdrlen;
++ jsval hdrval;
++
++ if(length > 7 && strncasecmp(header, "HTTP/1.", 7) == 0) {
++ if(length < 12) {
++ return CURLE_WRITE_ERROR;
++ }
++
++ memcpy(code, header+9, 3*sizeof(char));
++ code[3] = '\0';
++ state->http->last_status = atoi(code);
++
++ state->resp_headers = JS_NewArrayObject(state->cx, 0, NULL);
++ if(!state->resp_headers) {
++ return CURLE_WRITE_ERROR;
++ }
++
++ return length;
++ }
++
++ // We get a notice at the \r\n\r\n after headers.
++ if(length <= 2) {
++ return length;
++ }
++
++ // Append the new header to our array.
++ hdr = dec_string(state->cx, header, length);
++ if(!hdr) {
++ return CURLE_WRITE_ERROR;
++ }
++
++ if(!JS_GetArrayLength(state->cx, state->resp_headers, &hdrlen)) {
++ return CURLE_WRITE_ERROR;
++ }
++
++ hdrval = STRING_TO_JSVAL(hdr);
++ if(!JS_SetElement(state->cx, state->resp_headers, hdrlen, &hdrval)) {
++ return CURLE_WRITE_ERROR;
++ }
++
++ return length;
++}
++
++static size_t
++recv_body(void *ptr, size_t size, size_t nmem, void *data)
++{
++ CurlState* state = (CurlState*) data;
++ size_t length = size * nmem;
++ char* tmp = NULL;
++
++ if(!state->recvbuf) {
++ state->recvlen = 4096;
++ state->read = 0;
++ state->recvbuf = (char*) JS_malloc(state->cx, state->recvlen);
++ }
++
++ if(!state->recvbuf) {
++ return CURLE_WRITE_ERROR;
++ }
++
++ // +1 so we can add '\0' back up in the go function.
++ while(length+1 > state->recvlen - state->read) state->recvlen *= 2;
++ tmp = (char*) JS_realloc(state->cx, state->recvbuf, state->recvlen);
++ if(!tmp) return CURLE_WRITE_ERROR;
++ state->recvbuf = tmp;
++
++ memcpy(state->recvbuf + state->read, ptr, length);
++ state->read += length;
++ return length;
++}
++
++JSString*
++str_from_binary(JSContext* cx, char* data, size_t length)
++{
++ jschar* conv = (jschar*) JS_malloc(cx, length * sizeof(jschar));
++ JSString* ret = NULL;
++ size_t i;
++
++ if(!conv) return NULL;
++
++ for(i = 0; i < length; i++) {
++ conv[i] = (jschar) data[i];
++ }
++
++ ret = JS_NewUCString(cx, conv, length);
++ if(!ret) JS_free(cx, conv);
++
++ return ret;
++}
++
++#endif /* HAVE_CURL */
+Index: bigcouch-0.4.2.leap/couchjs/build/sm170.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/sm170.c 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,381 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++
++#include "http.h"
++#include "sm.h"
++#include "utf8.h"
++#include "util.h"
++
++
++#ifdef JS_THREADSAFE
++#define SETUP_REQUEST(cx) \
++ JS_SetContextThread(cx); \
++ JS_BeginRequest(cx);
++#define FINISH_REQUEST(cx) \
++ JS_EndRequest(cx); \
++ JS_ClearContextThread(cx);
++#else
++#define SETUP_REQUEST(cx)
++#define FINISH_REQUEST(cx)
++#endif
++
++
++static JSBool
++req_ctor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ return http_ctor(cx, obj);
++}
++
++
++static void
++req_dtor(JSContext* cx, JSObject* obj)
++{
++ http_dtor(cx, obj);
++}
++
++
++static JSBool
++req_open(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ JSBool ret = JS_FALSE;
++
++ if(argc == 2) {
++ ret = http_open(cx, obj, argv[0], argv[1], JSVAL_FALSE);
++ } else if(argc == 3) {
++ ret = http_open(cx, obj, argv[0], argv[1], argv[2]);
++ } else {
++ JS_ReportError(cx, "Invalid call to CouchHTTP.open");
++ }
++
++ *rval = JSVAL_VOID;
++ return ret;
++}
++
++
++static JSBool
++req_set_hdr(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ JSBool ret = JS_FALSE;
++ if(argc == 2) {
++ ret = http_set_hdr(cx, obj, argv[0], argv[1]);
++ } else {
++ JS_ReportError(cx, "Invalid call to CouchHTTP.set_header");
++ }
++
++ *rval = JSVAL_VOID;
++ return ret;
++}
++
++
++static JSBool
++req_send(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ JSBool ret = JS_FALSE;
++ if(argc == 1) {
++ ret = http_send(cx, obj, argv[0]);
++ } else {
++ JS_ReportError(cx, "Invalid call to CouchHTTP.send");
++ }
++
++ *rval = JSVAL_VOID;
++ return ret;
++}
++
++
++static JSBool
++req_status(JSContext* cx, JSObject* obj, jsval idval, jsval* rval)
++{
++ int status = http_status(cx, obj);
++ if(status < 0)
++ return JS_FALSE;
++
++ if(INT_FITS_IN_JSVAL(status)) {
++ *rval = INT_TO_JSVAL(status);
++ return JS_TRUE;
++ } else {
++ JS_ReportError(cx, "Invalid HTTP status.");
++ return JS_FALSE;
++ }
++}
++
++
++static JSBool
++evalcx(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
++{
++ JSString *str;
++ JSObject *sandbox;
++ JSContext *subcx;
++ const jschar *src;
++ size_t srclen;
++ JSBool ret = JS_FALSE;
++
++ couch_args* args = (couch_args*) JS_GetContextPrivate(cx);
++
++ sandbox = NULL;
++ if(!JS_ConvertArguments(cx, argc, argv, "S / o", &str, &sandbox)) {
++ return JS_FALSE;
++ }
++
++ subcx = JS_NewContext(JS_GetRuntime(cx), args->stack_size);
++ if(!subcx) {
++ JS_ReportOutOfMemory(cx);
++ return JS_FALSE;
++ }
++
++ SETUP_REQUEST(subcx);
++
++ src = JS_GetStringChars(str);
++ srclen = JS_GetStringLength(str);
++
++ if(!sandbox) {
++ sandbox = JS_NewObject(subcx, NULL, NULL, NULL);
++ if(!sandbox || !JS_InitStandardClasses(subcx, sandbox)) {
++ goto done;
++ }
++ }
++
++ if(srclen == 0) {
++ *rval = OBJECT_TO_JSVAL(sandbox);
++ } else {
++ JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, rval);
++ }
++
++ ret = JS_TRUE;
++
++done:
++ FINISH_REQUEST(subcx);
++ JS_DestroyContext(subcx);
++ return ret;
++}
++
++
++static JSBool
++gc(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ JS_GC(cx);
++ *rval = JSVAL_VOID;
++ return JS_TRUE;
++}
++
++
++static JSBool
++print(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ couch_print(cx, argc, argv);
++ *rval = JSVAL_VOID;
++ return JS_TRUE;
++}
++
++
++static JSBool
++quit(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ int exit_code = 0;
++ JS_ConvertArguments(cx, argc, argv, "/i", &exit_code);
++ exit(exit_code);
++}
++
++
++static JSBool
++readline(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ JSString* line;
++
++ /* GC Occasionally */
++ JS_MaybeGC(cx);
++
++ line = couch_readline(cx, stdin);
++ if(line == NULL) return JS_FALSE;
++
++ *rval = STRING_TO_JSVAL(line);
++ return JS_TRUE;
++}
++
++
++static JSBool
++seal(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ JSObject *target;
++ JSBool deep = JS_FALSE;
++
++ if(!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
++ return JS_FALSE;
++
++ if(!target) {
++ *rval = JSVAL_VOID;
++ return JS_TRUE;
++ }
++
++ if(JS_SealObject(cx, target, deep) != JS_TRUE)
++ return JS_FALSE;
++
++ *rval = JSVAL_VOID;
++ return JS_TRUE;
++}
++
++
++JSClass CouchHTTPClass = {
++ "CouchHTTP",
++ JSCLASS_HAS_PRIVATE
++ | JSCLASS_CONSTRUCT_PROTOTYPE
++ | JSCLASS_HAS_RESERVED_SLOTS(2),
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_EnumerateStub,
++ JS_ResolveStub,
++ JS_ConvertStub,
++ req_dtor,
++ JSCLASS_NO_OPTIONAL_MEMBERS
++};
++
++
++JSPropertySpec CouchHTTPProperties[] = {
++ {"status", 0, JSPROP_READONLY, req_status, NULL},
++ {0, 0, 0, 0, 0}
++};
++
++
++JSFunctionSpec CouchHTTPFunctions[] = {
++ {"_open", req_open, 3, 0, 0},
++ {"_setRequestHeader", req_set_hdr, 2, 0, 0},
++ {"_send", req_send, 1, 0, 0},
++ {0, 0, 0, 0, 0}
++};
++
++
++static JSClass global_class = {
++ "GlobalClass",
++ JSCLASS_GLOBAL_FLAGS,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_EnumerateStub,
++ JS_ResolveStub,
++ JS_ConvertStub,
++ JS_FinalizeStub,
++ JSCLASS_NO_OPTIONAL_MEMBERS
++};
++
++
++static JSFunctionSpec global_functions[] = {
++ {"evalcx", evalcx, 0, 0, 0},
++ {"gc", gc, 0, 0, 0},
++ {"print", print, 0, 0, 0},
++ {"quit", quit, 0, 0, 0},
++ {"readline", readline, 0, 0, 0},
++ {"seal", seal, 0, 0, 0},
++ {0, 0, 0, 0, 0}
++};
++
++
++int
++main(int argc, const char* argv[])
++{
++ JSRuntime* rt = NULL;
++ JSContext* cx = NULL;
++ JSObject* global = NULL;
++ JSObject* klass = NULL;
++ JSScript* script;
++ JSString* scriptsrc;
++ jschar* schars;
++ size_t slen;
++ jsval sroot;
++ jsval result;
++
++ couch_args* args = couch_parse_args(argc, argv);
++
++ rt = JS_NewRuntime(64L * 1024L * 1024L);
++ if(rt == NULL)
++ return 1;
++
++ cx = JS_NewContext(rt, args->stack_size);
++ if(cx == NULL)
++ return 1;
++
++ JS_SetContextPrivate(cx, args);
++ JS_SetErrorReporter(cx, couch_error);
++ JS_ToggleOptions(cx, JSOPTION_XML);
++
++ SETUP_REQUEST(cx);
++
++ global = JS_NewObject(cx, &global_class, NULL, NULL);
++ if(global == NULL)
++ return 1;
++
++ JS_SetGlobalObject(cx, global);
++
++ if(!JS_InitStandardClasses(cx, global))
++ return 1;
++
++ if(couch_load_funcs(cx, global, global_functions) != JS_TRUE)
++ return 1;
++
++ if(args->use_http) {
++ http_check_enabled();
++
++ klass = JS_InitClass(
++ cx, global,
++ NULL,
++ &CouchHTTPClass, req_ctor,
++ 0,
++ CouchHTTPProperties, CouchHTTPFunctions,
++ NULL, NULL
++ );
++
++ if(!klass)
++ {
++ fprintf(stderr, "Failed to initialize CouchHTTP class.\n");
++ exit(2);
++ }
++ }
++
++ // Convert script source to jschars.
++ scriptsrc = dec_string(cx, args->script, strlen(args->script));
++ if(!scriptsrc)
++ return 1;
++
++ schars = JS_GetStringChars(scriptsrc);
++ slen = JS_GetStringLength(scriptsrc);
++
++ // Root it so GC doesn't collect it.
++ sroot = STRING_TO_JSVAL(scriptsrc);
++ if(JS_AddRoot(cx, &sroot) != JS_TRUE) {
++ fprintf(stderr, "Internal root error.\n");
++ return 1;
++ }
++
++ // Compile and run
++ script = JS_CompileUCScript(cx, global, schars, slen, args->script_name, 1);
++ if(!script) {
++ fprintf(stderr, "Failed to compile script.\n");
++ return 1;
++ }
++
++ JS_ExecuteScript(cx, global, script, &result);
++
++ // Warning message if we don't remove it.
++ JS_RemoveRoot(cx, &sroot);
++
++ FINISH_REQUEST(cx);
++ JS_DestroyContext(cx);
++ JS_DestroyRuntime(rt);
++ JS_ShutDown();
++
++ return 0;
++}
+Index: bigcouch-0.4.2.leap/couchjs/build/SConscript
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/SConscript 2014-01-17 10:54:17.384970595 -0500
+@@ -0,0 +1,116 @@
++# Copyright 2010 Cloudant
++#
++# Licensed under the Apache License, Version 2.0 (the "License"); you may not
++# use this file except in compliance with the License. You may obtain a copy of
++# the License at
++#
++# http://www.apache.org/licenses/LICENSE-2.0
++#
++# Unless required by applicable law or agreed to in writing, software
++# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++# License for the specific language governing permissions and limitations under
++# the License.
++import os
++import commands
++
++def require_lib(name):
++ if not conf.CheckLib(name):
++ print 'Could not find required library', name
++ Exit(1)
++
++def runcmd(cmd):
++ return commands.getstatusoutput(cmd)
++
++env = Environment(CC="c++", CCFLAGS='-g -O2 -DXP_UNIX',
++ CPPPATH=os.getenv("CPPPATH"),
++ LINKFLAGS="-pthread")
++
++if os.uname()[0] == 'SunOS':
++ env['CC'] = '/usr/sfw/bin/gcc'
++ env['CCFLAGS'] += ' -I/opt/local/include'
++ env.Append(LINKFLAGS=['-L/opt/local/lib'])
++
++if os.uname()[0] == 'FreeBSD':
++ env['CCFLAGS'] += ' -I/usr/local/include'
++ env.Append(LINKFLAGS=['-L/usr/local/lib'])
++ env['LIB_DL'] = env['LIB_RT'] = ''
++ env['LIB_COMPAT'] = 'compat'
++
++if os.path.exists('/usr/bin/pkg-config'):
++ for pkg in ["mozilla-js-185", "mozilla-js"]:
++ (s1, output) = runcmd("/usr/bin/pkg-config %s --cflags" % pkg)
++ if s1 == 0:
++ env.Append(CCFLAGS=" " + output)
++ (s2, output) = runcmd("/usr/bin/pkg-config %s --libs-only-L" % pkg)
++ if s2 == 0:
++ env.Append(LINKFLAGS=output)
++ if s1 == 0 or s2 == 0:
++ break
++
++if not env.GetOption('clean'):
++ conf = Configure(env, config_h='config.h')
++
++ require_lib('m')
++ require_lib('pthread')
++ require_lib('nspr4')
++
++ ## check for SpiderMonkey development header
++ if conf.CheckHeader('mozjs/jsapi.h'):
++ jsapi = 'mozjs/jsapi.h'
++ elif conf.CheckHeader('js/jsapi.h'):
++ jsapi = 'js/jsapi.h'
++ elif conf.CheckHeader('jsapi.h'):
++ jsapi = 'jsapi.h'
++ else:
++ print 'Could not find jsapi.h.', \
++ 'Are Mozilla SpiderMonkey headers installed?'
++ Exit(1)
++
++ ## check for SpiderMonkey library as libjs or libmozjs
++ if not conf.CheckLibWithHeader('mozjs185-1.0', jsapi, 'c', autoadd=1):
++ if not conf.CheckLibWithHeader('mozjs', jsapi, 'c', autoadd=1):
++ if not conf.CheckLibWithHeader('js', jsapi, 'c', autoadd=1):
++ print 'Could not find JS library.', \
++ 'Is Mozilla SpiderMonkey installed?'
++ Exit(1)
++
++ ## Detect the version of SpiderMonkey we're using
++ jsheader = "#include <%s>" % jsapi
++ versions = [
++ ("JS_NewCompartmentAndGlobalObject", "SM185"),
++ ("JS_ThrowStopIteration", "SM180"),
++ ("JS_GetStringCharsAndLength", "SM170")
++ ]
++ for func, vsn in versions:
++ if conf.CheckDeclaration(func, jsheader):
++ conf.Define(vsn)
++ break
++
++ ## Find the proper type for JS script objects
++
++ if conf.CheckType("JSScript*", '#include "%s"' % jsapi):
++ conf.Define("JSSCRIPT_TYPE", "JSScript*")
++ else:
++ conf.Define("JSSCRIPT_TYPE", "JSObject*")
++
++ ## Check if curl is available
++ try:
++ vsn = runcmd("curl-config --version")[1]
++ vsn = vsn.split()[-1].strip().split(".")
++ vsn = tuple(map(int, vsn))
++ if vsn > (7, 18, 0):
++ require_lib('curl')
++ except:
++ pass
++
++ ## Define properties for -h / -V
++
++ vsn = "1.1.1-792-gc8a44ff"
++ conf.Define("PACKAGE_STRING", '"%s"' % vsn.rstrip())
++ conf.Define("PACKAGE_NAME", '"Cloudant BigCouch"')
++ conf.Define("PACKAGE_BUGREPORT", '"https://github.com/cloudant/bigcouch/issues"')
++
++ env = conf.Finish()
++
++env.Program('couchjs', ['main.c', 'http.c', 'utf8.c', 'util.c'])
+Index: bigcouch-0.4.2.leap/couchjs/build/sm.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/sm.h 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,13 @@
++#ifndef COUCHJS_SM_H
++#define COUCHJS_SM_H
++
++#include "config.h"
++#ifdef HAVE_JS_JSAPI_H
++#include <js/jsapi.h>
++#elif HAVE_MOZJS_JSAPI_H
++#include <mozjs/jsapi.h>
++#else
++#include <jsapi.h>
++#endif
++
++#endif // included sm.h
+Index: bigcouch-0.4.2.leap/couchjs/build/main.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/main.c 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,21 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#include "config.h"
++
++#if defined(SM185)
++#include "sm185.c"
++#elif defined(SM180)
++#include "sm180.c"
++#else
++#include "sm170.c"
++#endif
+Index: bigcouch-0.4.2.leap/couchjs/build/sm180.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/sm180.c 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,390 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++
++#include "http.h"
++#include "sm.h"
++#include "utf8.h"
++#include "util.h"
++
++
++#define SETUP_REQUEST(cx) \
++ JS_SetContextThread(cx); \
++ JS_BeginRequest(cx);
++#define FINISH_REQUEST(cx) \
++ JS_EndRequest(cx); \
++ JS_ClearContextThread(cx);
++
++
++static JSBool
++req_ctor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
++{
++ return http_ctor(cx, obj);
++}
++
++
++static void
++req_dtor(JSContext* cx, JSObject* obj)
++{
++ http_dtor(cx, obj);
++}
++
++
++static JSBool
++req_open(JSContext* cx, uintN argc, jsval* vp)
++{
++ JSObject* obj = JS_THIS_OBJECT(cx, vp);
++ jsval* argv = JS_ARGV(cx, vp);
++ JSBool ret = JS_FALSE;
++
++ if(argc == 2) {
++ ret = http_open(cx, obj, argv[0], argv[1], JSVAL_FALSE);
++ } else if(argc == 3) {
++ ret = http_open(cx, obj, argv[0], argv[1], argv[2]);
++ } else {
++ JS_ReportError(cx, "Invalid call to CouchHTTP.open");
++ }
++
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return ret;
++}
++
++
++static JSBool
++req_set_hdr(JSContext* cx, uintN argc, jsval* vp)
++{
++ JSObject* obj = JS_THIS_OBJECT(cx, vp);
++ jsval* argv = JS_ARGV(cx, vp);
++ JSBool ret = JS_FALSE;
++
++ if(argc == 2) {
++ ret = http_set_hdr(cx, obj, argv[0], argv[1]);
++ } else {
++ JS_ReportError(cx, "Invalid call to CouchHTTP.set_header");
++ }
++
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return ret;
++}
++
++
++static JSBool
++req_send(JSContext* cx, uintN argc, jsval* vp)
++{
++ JSObject* obj = JS_THIS_OBJECT(cx, vp);
++ jsval* argv = JS_ARGV(cx, vp);
++ JSBool ret = JS_FALSE;
++
++ if(argc == 1) {
++ ret = http_send(cx, obj, argv[0]);
++ } else {
++ JS_ReportError(cx, "Invalid call to CouchHTTP.send");
++ }
++
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return ret;
++}
++
++
++static JSBool
++req_status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
++{
++ int status = http_status(cx, obj);
++ if(status < 0)
++ return JS_FALSE;
++
++ if(INT_FITS_IN_JSVAL(status)) {
++ JS_SET_RVAL(cx, vp, INT_TO_JSVAL(status));
++ return JS_TRUE;
++ } else {
++ JS_ReportError(cx, "Invalid HTTP status.");
++ return JS_FALSE;
++ }
++}
++
++
++static JSBool
++evalcx(JSContext *cx, uintN argc, jsval* vp)
++{
++ jsval* argv = JS_ARGV(cx, vp);
++ JSString *str;
++ JSObject *sandbox;
++ JSContext *subcx;
++ const jschar *src;
++ size_t srclen;
++ jsval rval;
++ JSBool ret = JS_FALSE;
++
++ couch_args* args = (couch_args*) JS_GetContextPrivate(cx);
++
++ sandbox = NULL;
++ if(!JS_ConvertArguments(cx, argc, argv, "S / o", &str, &sandbox)) {
++ return JS_FALSE;
++ }
++
++ subcx = JS_NewContext(JS_GetRuntime(cx), args->stack_size);
++ if(!subcx) {
++ JS_ReportOutOfMemory(cx);
++ return JS_FALSE;
++ }
++
++ SETUP_REQUEST(subcx);
++
++ src = JS_GetStringChars(str);
++ srclen = JS_GetStringLength(str);
++
++ if(!sandbox) {
++ sandbox = JS_NewObject(subcx, NULL, NULL, NULL);
++ if(!sandbox || !JS_InitStandardClasses(subcx, sandbox)) {
++ goto done;
++ }
++ }
++
++ if(srclen == 0) {
++ JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(sandbox));
++ } else {
++ JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, &rval);
++ JS_SET_RVAL(cx, vp, rval);
++ }
++
++ ret = JS_TRUE;
++
++done:
++ FINISH_REQUEST(subcx);
++ JS_DestroyContext(subcx);
++ return ret;
++}
++
++
++static JSBool
++gc(JSContext* cx, uintN argc, jsval* vp)
++{
++ JS_GC(cx);
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return JS_TRUE;
++}
++
++
++static JSBool
++print(JSContext* cx, uintN argc, jsval* vp)
++{
++ jsval* argv = JS_ARGV(cx, vp);
++ couch_print(cx, argc, argv);
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return JS_TRUE;
++}
++
++
++static JSBool
++quit(JSContext* cx, uintN argc, jsval* vp)
++{
++ jsval* argv = JS_ARGV(cx, vp);
++ int exit_code = 0;
++ JS_ConvertArguments(cx, argc, argv, "/i", &exit_code);
++ exit(exit_code);
++}
++
++
++static JSBool
++readline(JSContext* cx, uintN argc, jsval* vp)
++{
++ JSString* line;
++
++ /* GC Occasionally */
++ JS_MaybeGC(cx);
++
++ line = couch_readline(cx, stdin);
++ if(line == NULL) return JS_FALSE;
++
++ JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(line));
++ return JS_TRUE;
++}
++
++
++static JSBool
++seal(JSContext* cx, uintN argc, jsval* vp)
++{
++ jsval* argv = JS_ARGV(cx, vp);
++ JSObject *target;
++ JSBool deep = JS_FALSE;
++
++ if(!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
++ return JS_FALSE;
++
++ if(!target) {
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return JS_TRUE;
++ }
++
++ if(JS_SealObject(cx, target, deep) != JS_TRUE)
++ return JS_FALSE;
++
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return JS_TRUE;
++}
++
++
++JSClass CouchHTTPClass = {
++ "CouchHTTP",
++ JSCLASS_HAS_PRIVATE
++ | JSCLASS_CONSTRUCT_PROTOTYPE
++ | JSCLASS_HAS_RESERVED_SLOTS(2),
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_EnumerateStub,
++ JS_ResolveStub,
++ JS_ConvertStub,
++ req_dtor,
++ JSCLASS_NO_OPTIONAL_MEMBERS
++};
++
++
++JSPropertySpec CouchHTTPProperties[] = {
++ {"status", 0, JSPROP_READONLY, req_status, NULL},
++ {0, 0, 0, 0, 0}
++};
++
++
++JSFunctionSpec CouchHTTPFunctions[] = {
++ JS_FS("_open", (JSNative) req_open, 3, JSFUN_FAST_NATIVE, 0),
++ JS_FS("_setRequestHeader", (JSNative) req_set_hdr, 2, JSFUN_FAST_NATIVE, 0),
++ JS_FS("_send", (JSNative) req_send, 1, JSFUN_FAST_NATIVE, 0),
++ JS_FS_END
++};
++
++
++static JSClass global_class = {
++ "GlobalClass",
++ JSCLASS_GLOBAL_FLAGS,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_EnumerateStub,
++ JS_ResolveStub,
++ JS_ConvertStub,
++ JS_FinalizeStub,
++ JSCLASS_NO_OPTIONAL_MEMBERS
++};
++
++
++static JSFunctionSpec global_functions[] = {
++ JS_FS("evalcx", (JSNative) evalcx, 0, JSFUN_FAST_NATIVE, 0),
++ JS_FS("gc", (JSNative) gc, 0, JSFUN_FAST_NATIVE, 0),
++ JS_FS("print", (JSNative) print, 0, JSFUN_FAST_NATIVE, 0),
++ JS_FS("quit", (JSNative) quit, 0, JSFUN_FAST_NATIVE, 0),
++ JS_FS("readline", (JSNative) readline, 0, JSFUN_FAST_NATIVE, 0),
++ JS_FS("seal", (JSNative) seal, 0, JSFUN_FAST_NATIVE, 0),
++ JS_FS_END
++};
++
++
++int
++main(int argc, const char* argv[])
++{
++ JSRuntime* rt = NULL;
++ JSContext* cx = NULL;
++ JSObject* global = NULL;
++ JSObject* klass = NULL;
++ JSScript* script;
++ JSString* scriptsrc;
++ jschar* schars;
++ size_t slen;
++ jsval sroot;
++ jsval result;
++
++ couch_args* args = couch_parse_args(argc, argv);
++
++ rt = JS_NewRuntime(64L * 1024L * 1024L);
++ if(rt == NULL)
++ return 1;
++
++ cx = JS_NewContext(rt, args->stack_size);
++ if(cx == NULL)
++ return 1;
++
++ JS_SetContextPrivate(cx, args);
++ JS_SetErrorReporter(cx, couch_error);
++ JS_ToggleOptions(cx, JSOPTION_XML);
++
++ SETUP_REQUEST(cx);
++
++ global = JS_NewObject(cx, &global_class, NULL, NULL);
++ if(global == NULL)
++ return 1;
++
++ JS_SetGlobalObject(cx, global);
++
++ if(!JS_InitStandardClasses(cx, global))
++ return 1;
++
++ if(couch_load_funcs(cx, global, global_functions) != JS_TRUE)
++ return 1;
++
++ if(args->use_http) {
++ http_check_enabled();
++
++ klass = JS_InitClass(
++ cx, global,
++ NULL,
++ &CouchHTTPClass, req_ctor,
++ 0,
++ CouchHTTPProperties, CouchHTTPFunctions,
++ NULL, NULL
++ );
++
++ if(!klass)
++ {
++ fprintf(stderr, "Failed to initialize CouchHTTP class.\n");
++ exit(2);
++ }
++ }
++
++ // Convert script source to jschars.
++ scriptsrc = dec_string(cx, args->script, strlen(args->script));
++ if(!scriptsrc)
++ return 1;
++
++ schars = JS_GetStringChars(scriptsrc);
++ slen = JS_GetStringLength(scriptsrc);
++
++ // Root it so GC doesn't collect it.
++ sroot = STRING_TO_JSVAL(scriptsrc);
++ if(JS_AddRoot(cx, &sroot) != JS_TRUE) {
++ fprintf(stderr, "Internal root error.\n");
++ return 1;
++ }
++
++ // Compile and run
++ script = JS_CompileUCScript(cx, global, schars, slen, args->script_name, 1);
++ if(!script) {
++ fprintf(stderr, "Failed to compile script.\n");
++ return 1;
++ }
++
++ JS_ExecuteScript(cx, global, script, &result);
++
++ // Warning message if we don't remove it.
++ JS_RemoveRoot(cx, &sroot);
++
++ FINISH_REQUEST(cx);
++ JS_DestroyContext(cx);
++ JS_DestroyRuntime(rt);
++ JS_ShutDown();
++
++ return 0;
++}
+Index: bigcouch-0.4.2.leap/couchjs/build/help.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/help.h 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,82 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#ifndef COUCHJS_HELP_H
++#define COUCHJS_HELP_H
++
++#include <libgen.h>
++
++#include "config.h"
++
++static const char VERSION_TEMPLATE[] =
++ "%s - %s\n"
++ "\n"
++ "Licensed under the Apache License, Version 2.0 (the \"License\"); you may "
++ "not use\n"
++ "this file except in compliance with the License. You may obtain a copy of"
++ "the\n"
++ "License at\n"
++ "\n"
++ " http://www.apache.org/licenses/LICENSE-2.0\n"
++ "\n"
++ "Unless required by applicable law or agreed to in writing, software "
++ "distributed\n"
++ "under the License is distributed on an \"AS IS\" BASIS, WITHOUT "
++ "WARRANTIES OR\n"
++ "CONDITIONS OF ANY KIND, either express or implied. See the License "
++ "for the\n"
++ "specific language governing permissions and limitations under the "
++ "License.\n";
++
++static const char USAGE_TEMPLATE[] =
++ "Usage: %s [FILE]\n"
++ "\n"
++ "The %s command runs the %s JavaScript interpreter.\n"
++ "\n"
++ "The exit status is 0 for success or 1 for failure.\n"
++ "\n"
++ "Options:\n"
++ "\n"
++ " -h display a short help message and exit\n"
++ " -V display version information and exit\n"
++ " -H enable %s cURL bindings (only avaiable\n"
++ " if package was built with cURL available)\n"
++ " -S SIZE specify that the interpreter should set the\n"
++ " stack quota for JS contexts to SIZE bytes\n"
++ "\n"
++ "Report bugs at <%s>.\n";
++
++#define BASENAME basename((char*)argv[0])
++
++#define couch_version(basename) \
++ fprintf( \
++ stdout, \
++ VERSION_TEMPLATE, \
++ basename, \
++ PACKAGE_STRING)
++
++#define DISPLAY_VERSION couch_version(BASENAME)
++
++
++#define couch_usage(basename) \
++ fprintf( \
++ stdout, \
++ USAGE_TEMPLATE, \
++ basename, \
++ basename, \
++ PACKAGE_NAME, \
++ basename, \
++ PACKAGE_BUGREPORT)
++
++#define DISPLAY_USAGE couch_usage(BASENAME)
++
++#endif // Included help.h
+Index: bigcouch-0.4.2.leap/couchjs/build/utf8.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/utf8.c 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,291 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#include "config.h"
++#include "sm.h"
++
++static int
++enc_char(uint8 *utf8Buffer, uint32 ucs4Char)
++{
++ int utf8Length = 1;
++
++ if (ucs4Char < 0x80)
++ {
++ *utf8Buffer = (uint8)ucs4Char;
++ }
++ else
++ {
++ int i;
++ uint32 a = ucs4Char >> 11;
++ utf8Length = 2;
++ while(a)
++ {
++ a >>= 5;
++ utf8Length++;
++ }
++ i = utf8Length;
++ while(--i)
++ {
++ utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80);
++ ucs4Char >>= 6;
++ }
++ *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
++ }
++
++ return utf8Length;
++}
++
++static JSBool
++enc_charbuf(const jschar* src, size_t srclen, char* dst, size_t* dstlenp)
++{
++ size_t i;
++ size_t utf8Len;
++ size_t dstlen = *dstlenp;
++ size_t origDstlen = dstlen;
++ jschar c;
++ jschar c2;
++ uint32 v;
++ uint8 utf8buf[6];
++
++ if(!dst)
++ {
++ dstlen = origDstlen = (size_t) -1;
++ }
++
++ while(srclen)
++ {
++ c = *src++;
++ srclen--;
++
++ if((c >= 0xDC00) && (c <= 0xDFFF)) goto bad_surrogate;
++
++ if(c < 0xD800 || c > 0xDBFF)
++ {
++ v = c;
++ }
++ else
++ {
++ if(srclen < 1) goto buffer_too_small;
++ c2 = *src++;
++ srclen--;
++ if ((c2 < 0xDC00) || (c2 > 0xDFFF))
++ {
++ c = c2;
++ goto bad_surrogate;
++ }
++ v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
++ }
++ if(v < 0x0080)
++ {
++ /* no encoding necessary - performance hack */
++ if(!dstlen) goto buffer_too_small;
++ if(dst) *dst++ = (char) v;
++ utf8Len = 1;
++ }
++ else
++ {
++ utf8Len = enc_char(utf8buf, v);
++ if(utf8Len > dstlen) goto buffer_too_small;
++ if(dst)
++ {
++ for (i = 0; i < utf8Len; i++)
++ {
++ *dst++ = (char) utf8buf[i];
++ }
++ }
++ }
++ dstlen -= utf8Len;
++ }
++
++ *dstlenp = (origDstlen - dstlen);
++ return JS_TRUE;
++
++bad_surrogate:
++ *dstlenp = (origDstlen - dstlen);
++ return JS_FALSE;
++
++buffer_too_small:
++ *dstlenp = (origDstlen - dstlen);
++ return JS_FALSE;
++}
++
++char*
++enc_string(JSContext* cx, jsval arg, size_t* buflen)
++{
++ JSString* str = NULL;
++ const jschar* src = NULL;
++ char* bytes = NULL;
++ size_t srclen = 0;
++ size_t byteslen = 0;
++
++ str = JS_ValueToString(cx, arg);
++ if(!str) goto error;
++
++#ifdef SM185
++ src = JS_GetStringCharsAndLength(cx, str, &srclen);
++#else
++ src = JS_GetStringChars(str);
++ srclen = JS_GetStringLength(str);
++#endif
++
++ if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error;
++
++ bytes = (char*) JS_malloc(cx, (byteslen) + 1);
++ bytes[byteslen] = 0;
++
++ if(!enc_charbuf(src, srclen, bytes, &byteslen)) goto error;
++
++ if(buflen) *buflen = byteslen;
++ goto success;
++
++error:
++ if(bytes != NULL) JS_free(cx, bytes);
++ bytes = NULL;
++
++success:
++ return bytes;
++}
++
++static uint32
++dec_char(const uint8 *utf8Buffer, int utf8Length)
++{
++ uint32 ucs4Char;
++ uint32 minucs4Char;
++
++ /* from Unicode 3.1, non-shortest form is illegal */
++ static const uint32 minucs4Table[] = {
++ 0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
++ };
++
++ if (utf8Length == 1)
++ {
++ ucs4Char = *utf8Buffer;
++ }
++ else
++ {
++ ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
++ minucs4Char = minucs4Table[utf8Length-2];
++ while(--utf8Length)
++ {
++ ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
++ }
++ if(ucs4Char < minucs4Char || ucs4Char == 0xFFFE || ucs4Char == 0xFFFF)
++ {
++ ucs4Char = 0xFFFD;
++ }
++ }
++
++ return ucs4Char;
++}
++
++static JSBool
++dec_charbuf(const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
++{
++ uint32 v;
++ size_t offset = 0;
++ size_t j;
++ size_t n;
++ size_t dstlen = *dstlenp;
++ size_t origDstlen = dstlen;
++
++ if(!dst) dstlen = origDstlen = (size_t) -1;
++
++ while(srclen)
++ {
++ v = (uint8) *src;
++ n = 1;
++
++ if(v & 0x80)
++ {
++ while(v & (0x80 >> n))
++ {
++ n++;
++ }
++
++ if(n > srclen) goto buffer_too_small;
++ if(n == 1 || n > 6) goto bad_character;
++
++ for(j = 1; j < n; j++)
++ {
++ if((src[j] & 0xC0) != 0x80) goto bad_character;
++ }
++
++ v = dec_char((const uint8 *) src, n);
++ if(v >= 0x10000)
++ {
++ v -= 0x10000;
++
++ if(v > 0xFFFFF || dstlen < 2)
++ {
++ *dstlenp = (origDstlen - dstlen);
++ return JS_FALSE;
++ }
++
++ if(dstlen < 2) goto buffer_too_small;
++
++ if(dst)
++ {
++ *dst++ = (jschar)((v >> 10) + 0xD800);
++ v = (jschar)((v & 0x3FF) + 0xDC00);
++ }
++ dstlen--;
++ }
++ }
++
++ if(!dstlen) goto buffer_too_small;
++ if(dst) *dst++ = (jschar) v;
++
++ dstlen--;
++ offset += n;
++ src += n;
++ srclen -= n;
++ }
++
++ *dstlenp = (origDstlen - dstlen);
++ return JS_TRUE;
++
++bad_character:
++ *dstlenp = (origDstlen - dstlen);
++ return JS_FALSE;
++
++buffer_too_small:
++ *dstlenp = (origDstlen - dstlen);
++ return JS_FALSE;
++}
++
++JSString*
++dec_string(JSContext* cx, const char* bytes, size_t byteslen)
++{
++ JSString* str = NULL;
++ jschar* chars = NULL;
++ size_t charslen;
++
++ if(!dec_charbuf(bytes, byteslen, NULL, &charslen)) goto error;
++
++ chars = (jschar*) JS_malloc(cx, (charslen + 1) * sizeof(jschar));
++ if(!chars) return NULL;
++ chars[charslen] = 0;
++
++ if(!dec_charbuf(bytes, byteslen, chars, &charslen)) goto error;
++
++ str = JS_NewUCString(cx, chars, charslen - 1);
++ if(!str) goto error;
++
++ goto success;
++
++error:
++ if(chars != NULL) JS_free(cx, chars);
++ str = NULL;
++
++success:
++ return str;
++}
+Index: bigcouch-0.4.2.leap/couchjs/build/util.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/util.c 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,250 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#include <stdlib.h>
++#include <string.h>
++
++#include "help.h"
++#include "util.h"
++#include "utf8.h"
++
++
++char*
++slurp_file(char* buf, const char* file)
++{
++ FILE* fp;
++ char fbuf[16384];
++ char* tmp;
++ size_t nread = 0;
++ size_t buflen = 0;
++
++ if(strcmp(file, "-") == 0) {
++ fp = stdin;
++ } else {
++ fp = fopen(file, "r");
++ if(fp == NULL) {
++ fprintf(stderr, "Failed to read file: %s\n", file);
++ exit(3);
++ }
++ }
++
++ while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
++ if(buf == NULL) {
++ buflen = nread;
++ buf = (char*) malloc(nread + 1);
++ if(buf == NULL) {
++ fprintf(stderr, "Out of memory.\n");
++ exit(3);
++ }
++ memcpy(buf, fbuf, buflen);
++ buf[buflen] = '\0';
++ } else {
++ buflen = strlen(buf);
++ tmp = (char*) malloc(buflen + nread + 1);
++ if(tmp == NULL) {
++ fprintf(stderr, "Out of memory.\n");
++ exit(3);
++ }
++ memcpy(tmp, buf, buflen);
++ memcpy(tmp+buflen, fbuf, nread);
++ tmp[buflen+nread] = '\0';
++ free(buf);
++ buf = tmp;
++ }
++ }
++ return buf;
++}
++
++couch_args*
++couch_parse_args(int argc, const char* argv[])
++{
++ couch_args* args;
++ int i = 1;
++
++ args = (couch_args*) malloc(sizeof(couch_args));
++ if(args == NULL)
++ return NULL;
++
++ memset(args, '\0', sizeof(couch_args));
++ args->stack_size = 8L * 1024L;
++
++ while(i < argc) {
++ if(strcmp("-h", argv[i]) == 0) {
++ DISPLAY_USAGE;
++ exit(0);
++ } else if(strcmp("-V", argv[i]) == 0) {
++ DISPLAY_VERSION;
++ exit(0);
++ } else if(strcmp("-H", argv[i]) == 0) {
++ args->use_http = 1;
++ } else if(strcmp("-S", argv[i]) == 0) {
++ args->stack_size = atoi(argv[++i]);
++ if(args->stack_size <= 0) {
++ fprintf(stderr, "Invalid stack size.\n");
++ exit(2);
++ }
++ } else if(strcmp("--", argv[i]) == 0) {
++ i++;
++ break;
++ } else {
++ break;
++ }
++ i++;
++ }
++
++ while(i < argc) {
++ args->script = slurp_file(args->script, argv[i]);
++ if(args->script_name == NULL) {
++ if(strcmp(argv[i], "-") == 0) {
++ args->script_name = "<stdin>";
++ } else {
++ args->script_name = argv[i];
++ }
++ } else {
++ args->script_name = "<multiple_files>";
++ }
++ i++;
++ }
++
++ if(args->script_name == NULL || args->script == NULL) {
++ DISPLAY_USAGE;
++ exit(3);
++ }
++
++ return args;
++}
++
++
++int
++couch_fgets(char* buf, int size, FILE* fp)
++{
++ int n, i, c;
++
++ if(size <= 0) return -1;
++ n = size - 1;
++
++ for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
++ buf[i] = c;
++ if(c == '\n') {
++ i++;
++ break;
++ }
++ }
++
++ buf[i] = '\0';
++ return i;
++}
++
++
++JSString*
++couch_readline(JSContext* cx, FILE* fp)
++{
++ JSString* str;
++ char* bytes = NULL;
++ char* tmp = NULL;
++ size_t used = 0;
++ size_t byteslen = 256;
++ size_t readlen = 0;
++
++ bytes = (char*) JS_malloc(cx, byteslen);
++ if(bytes == NULL) return NULL;
++
++ while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
++ used += readlen;
++
++ if(bytes[used-1] == '\n') {
++ bytes[used-1] = '\0';
++ break;
++ }
++
++ // Double our buffer and read more.
++ byteslen *= 2;
++ tmp = (char*) JS_realloc(cx, bytes, byteslen);
++ if(!tmp) {
++ JS_free(cx, bytes);
++ return NULL;
++ }
++
++ bytes = tmp;
++ }
++
++ // Treat empty strings specially
++ if(used == 0) {
++ JS_free(cx, bytes);
++ return JSVAL_TO_STRING(JS_GetEmptyStringValue(cx));
++ }
++
++ // Shring the buffer to the actual data size
++ tmp = (char*) JS_realloc(cx, bytes, used);
++ if(!tmp) {
++ JS_free(cx, bytes);
++ return NULL;
++ }
++ bytes = tmp;
++ byteslen = used;
++
++ str = dec_string(cx, bytes, byteslen);
++ JS_free(cx, bytes);
++ return str;
++}
++
++
++JSObject*
++couch_readfile(JSContext* cx, FILE* fp)
++{
++ return NULL;
++}
++
++
++void
++couch_print(JSContext* cx, uintN argc, jsval* argv)
++{
++ char *bytes;
++ uintN i;
++
++ for(i = 0; i < argc; i++)
++ {
++ bytes = enc_string(cx, argv[i], NULL);
++ if(!bytes) return;
++
++ fprintf(stdout, "%s%s", i ? " " : "", bytes);
++ JS_free(cx, bytes);
++ }
++
++ fputc('\n', stdout);
++ fflush(stdout);
++}
++
++
++void
++couch_error(JSContext* cx, const char* mesg, JSErrorReport* report)
++{
++ if(!report || !JSREPORT_IS_WARNING(report->flags))
++ {
++ fprintf(stderr, "[couchjs] %s\n", mesg);
++ }
++}
++
++
++JSBool
++couch_load_funcs(JSContext* cx, JSObject* obj, JSFunctionSpec* funcs)
++{
++ JSFunctionSpec* f;
++ for(f = funcs; f->name != NULL; f++) {
++ if(!JS_DefineFunction(cx, obj, f->name, f->call, f->nargs, f->flags)) {
++ fprintf(stderr, "Failed to create function: %s\n", f->name);
++ return JS_FALSE;
++ }
++ }
++ return JS_TRUE;
++}
++
+Index: bigcouch-0.4.2.leap/couchjs/build/http.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/http.h 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,26 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#ifndef COUCH_JS_HTTP_H
++#define COUCH_JS_HTTP_H
++
++#include "sm.h"
++
++void http_check_enabled();
++JSBool http_ctor(JSContext* cx, JSObject* req);
++void http_dtor(JSContext* cx, JSObject* req);
++JSBool http_open(JSContext* cx, JSObject* req, jsval mth, jsval url, jsval snc);
++JSBool http_set_hdr(JSContext* cx, JSObject* req, jsval name, jsval val);
++JSBool http_send(JSContext* cx, JSObject* req, jsval body);
++int http_status(JSContext* cx, JSObject* req);
++
++#endif
+Index: bigcouch-0.4.2.leap/couchjs/build/sm185.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/sm185.c 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,404 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++
++#include "http.h"
++#include "sm.h"
++#include "utf8.h"
++#include "util.h"
++
++
++#define SETUP_REQUEST(cx) \
++ JS_SetContextThread(cx); \
++ JS_BeginRequest(cx);
++#define FINISH_REQUEST(cx) \
++ JS_EndRequest(cx); \
++ JS_ClearContextThread(cx);
++
++
++static JSClass global_class = {
++ "GlobalClass",
++ JSCLASS_GLOBAL_FLAGS,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_StrictPropertyStub,
++ JS_EnumerateStub,
++ JS_ResolveStub,
++ JS_ConvertStub,
++ JS_FinalizeStub,
++ JSCLASS_NO_OPTIONAL_MEMBERS
++};
++
++
++static JSBool
++req_ctor(JSContext* cx, uintN argc, jsval* vp)
++{
++ JSBool ret;
++ JSObject* obj = JS_NewObjectForConstructor(cx, vp);
++ if(!obj) {
++ JS_ReportError(cx, "Failed to create CouchHTTP instance.\n");
++ return JS_FALSE;
++ }
++ ret = http_ctor(cx, obj);
++ JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
++ return ret;
++}
++
++
++static void
++req_dtor(JSContext* cx, JSObject* obj)
++{
++ http_dtor(cx, obj);
++}
++
++
++static JSBool
++req_open(JSContext* cx, uintN argc, jsval* vp)
++{
++ JSObject* obj = JS_THIS_OBJECT(cx, vp);
++ jsval* argv = JS_ARGV(cx, vp);
++ JSBool ret = JS_FALSE;
++
++ if(argc == 2) {
++ ret = http_open(cx, obj, argv[0], argv[1], JSVAL_FALSE);
++ } else if(argc == 3) {
++ ret = http_open(cx, obj, argv[0], argv[1], argv[2]);
++ } else {
++ JS_ReportError(cx, "Invalid call to CouchHTTP.open");
++ }
++
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return ret;
++}
++
++
++static JSBool
++req_set_hdr(JSContext* cx, uintN argc, jsval* vp)
++{
++ JSObject* obj = JS_THIS_OBJECT(cx, vp);
++ jsval* argv = JS_ARGV(cx, vp);
++ JSBool ret = JS_FALSE;
++
++ if(argc == 2) {
++ ret = http_set_hdr(cx, obj, argv[0], argv[1]);
++ } else {
++ JS_ReportError(cx, "Invalid call to CouchHTTP.set_header");
++ }
++
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return ret;
++}
++
++
++static JSBool
++req_send(JSContext* cx, uintN argc, jsval* vp)
++{
++ JSObject* obj = JS_THIS_OBJECT(cx, vp);
++ jsval* argv = JS_ARGV(cx, vp);
++ JSBool ret = JS_FALSE;
++
++ if(argc == 1) {
++ ret = http_send(cx, obj, argv[0]);
++ } else {
++ JS_ReportError(cx, "Invalid call to CouchHTTP.send");
++ }
++
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return ret;
++}
++
++
++static JSBool
++req_status(JSContext* cx, JSObject* obj, jsid pid, jsval* vp)
++{
++ int status = http_status(cx, obj);
++ if(status < 0)
++ return JS_FALSE;
++
++ JS_SET_RVAL(cx, vp, INT_TO_JSVAL(status));
++ return JS_TRUE;
++}
++
++
++static JSBool
++evalcx(JSContext *cx, uintN argc, jsval* vp)
++{
++ jsval* argv = JS_ARGV(cx, vp);
++ JSString* str;
++ JSObject* sandbox;
++ JSObject* global;
++ JSContext* subcx;
++ JSCrossCompartmentCall* call = NULL;
++ const jschar* src;
++ size_t srclen;
++ jsval rval;
++ JSBool ret = JS_FALSE;
++
++ couch_args* args = (couch_args*) JS_GetContextPrivate(cx);
++
++ sandbox = NULL;
++ if(!JS_ConvertArguments(cx, argc, argv, "S / o", &str, &sandbox)) {
++ return JS_FALSE;
++ }
++
++ subcx = JS_NewContext(JS_GetRuntime(cx), args->stack_size);
++ if(!subcx) {
++ JS_ReportOutOfMemory(cx);
++ return JS_FALSE;
++ }
++
++ SETUP_REQUEST(subcx);
++
++ src = JS_GetStringCharsAndLength(cx, str, &srclen);
++
++ // Re-use the compartment associated with the main context,
++ // rather than creating a new compartment */
++ global = JS_GetGlobalObject(cx);
++ if(global == NULL) goto done;
++ call = JS_EnterCrossCompartmentCall(subcx, global);
++
++ if(!sandbox) {
++ sandbox = JS_NewGlobalObject(subcx, &global_class);
++ if(!sandbox || !JS_InitStandardClasses(subcx, sandbox)) {
++ goto done;
++ }
++ }
++
++ if(srclen == 0) {
++ JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(sandbox));
++ } else {
++ JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, &rval);
++ JS_SET_RVAL(cx, vp, rval);
++ }
++
++ ret = JS_TRUE;
++
++done:
++ JS_LeaveCrossCompartmentCall(call);
++ FINISH_REQUEST(subcx);
++ JS_DestroyContext(subcx);
++ return ret;
++}
++
++
++static JSBool
++gc(JSContext* cx, uintN argc, jsval* vp)
++{
++ JS_GC(cx);
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return JS_TRUE;
++}
++
++
++static JSBool
++print(JSContext* cx, uintN argc, jsval* vp)
++{
++ jsval* argv = JS_ARGV(cx, vp);
++ couch_print(cx, argc, argv);
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return JS_TRUE;
++}
++
++
++static JSBool
++quit(JSContext* cx, uintN argc, jsval* vp)
++{
++ jsval* argv = JS_ARGV(cx, vp);
++ int exit_code = 0;
++ JS_ConvertArguments(cx, argc, argv, "/i", &exit_code);
++ exit(exit_code);
++}
++
++
++static JSBool
++readline(JSContext* cx, uintN argc, jsval* vp)
++{
++ JSString* line;
++
++ /* GC Occasionally */
++ JS_MaybeGC(cx);
++
++ line = couch_readline(cx, stdin);
++ if(line == NULL) return JS_FALSE;
++
++ JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(line));
++ return JS_TRUE;
++}
++
++
++static JSBool
++seal(JSContext* cx, uintN argc, jsval* vp)
++{
++ jsval* argv = JS_ARGV(cx, vp);
++ JSObject *target;
++ JSBool deep = JS_FALSE;
++ JSBool ret;
++
++ if(!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
++ return JS_FALSE;
++
++ if(!target) {
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return JS_TRUE;
++ }
++
++
++ ret = deep ? JS_DeepFreezeObject(cx, target) : JS_FreezeObject(cx, target);
++ JS_SET_RVAL(cx, vp, JSVAL_VOID);
++ return ret;
++}
++
++
++JSClass CouchHTTPClass = {
++ "CouchHTTP",
++ JSCLASS_HAS_PRIVATE
++ | JSCLASS_CONSTRUCT_PROTOTYPE
++ | JSCLASS_HAS_RESERVED_SLOTS(2),
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_PropertyStub,
++ JS_StrictPropertyStub,
++ JS_EnumerateStub,
++ JS_ResolveStub,
++ JS_ConvertStub,
++ req_dtor,
++ JSCLASS_NO_OPTIONAL_MEMBERS
++};
++
++
++JSPropertySpec CouchHTTPProperties[] = {
++ {"status", 0, JSPROP_READONLY, req_status, NULL},
++ {0, 0, 0, 0, 0}
++};
++
++
++JSFunctionSpec CouchHTTPFunctions[] = {
++ JS_FS("_open", req_open, 3, 0),
++ JS_FS("_setRequestHeader", req_set_hdr, 2, 0),
++ JS_FS("_send", req_send, 1, 0),
++ JS_FS_END
++};
++
++
++static JSFunctionSpec global_functions[] = {
++ JS_FS("evalcx", evalcx, 0, 0),
++ JS_FS("gc", gc, 0, 0),
++ JS_FS("print", print, 0, 0),
++ JS_FS("quit", quit, 0, 0),
++ JS_FS("readline", readline, 0, 0),
++ JS_FS("seal", seal, 0, 0),
++ JS_FS_END
++};
++
++
++int
++main(int argc, const char* argv[])
++{
++ JSRuntime* rt = NULL;
++ JSContext* cx = NULL;
++ JSObject* global = NULL;
++ JSCrossCompartmentCall *call = NULL;
++ JSObject* klass = NULL;
++ JSSCRIPT_TYPE script;
++ JSString* scriptsrc;
++ const jschar* schars;
++ size_t slen;
++ jsval sroot;
++ jsval result;
++
++ couch_args* args = couch_parse_args(argc, argv);
++
++ rt = JS_NewRuntime(64L * 1024L * 1024L);
++ if(rt == NULL)
++ return 1;
++
++ cx = JS_NewContext(rt, args->stack_size);
++ if(cx == NULL)
++ return 1;
++
++ JS_SetContextPrivate(cx, args);
++ JS_SetErrorReporter(cx, couch_error);
++ JS_ToggleOptions(cx, JSOPTION_XML);
++
++ SETUP_REQUEST(cx);
++
++ global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
++ if(global == NULL)
++ return 1;
++
++ call = JS_EnterCrossCompartmentCall(cx, global);
++
++ JS_SetGlobalObject(cx, global);
++
++ if(!JS_InitStandardClasses(cx, global))
++ return 1;
++
++ if(couch_load_funcs(cx, global, global_functions) != JS_TRUE)
++ return 1;
++
++ if(args->use_http) {
++ http_check_enabled();
++
++ klass = JS_InitClass(
++ cx, global,
++ NULL,
++ &CouchHTTPClass, req_ctor,
++ 0,
++ CouchHTTPProperties, CouchHTTPFunctions,
++ NULL, NULL
++ );
++
++ if(!klass)
++ {
++ fprintf(stderr, "Failed to initialize CouchHTTP class.\n");
++ exit(2);
++ }
++ }
++
++ // Convert script source to jschars.
++ scriptsrc = dec_string(cx, args->script, strlen(args->script));
++ if(!scriptsrc)
++ return 1;
++
++ schars = JS_GetStringCharsAndLength(cx, scriptsrc, &slen);
++
++ // Root it so GC doesn't collect it.
++ sroot = STRING_TO_JSVAL(scriptsrc);
++ if(JS_AddValueRoot(cx, &sroot) != JS_TRUE) {
++ fprintf(stderr, "Internal root error.\n");
++ return 1;
++ }
++
++ // Compile and run
++ script = JS_CompileUCScript(cx, global, schars, slen, args->script_name, 1);
++ if(!script) {
++ fprintf(stderr, "Failed to compile script.\n");
++ return 1;
++ }
++
++ JS_ExecuteScript(cx, global, script, &result);
++
++ // Warning message if we don't remove it.
++ JS_RemoveValueRoot(cx, &sroot);
++
++ JS_LeaveCrossCompartmentCall(call);
++ FINISH_REQUEST(cx);
++ JS_DestroyContext(cx);
++ JS_DestroyRuntime(rt);
++ JS_ShutDown();
++
++ return 0;
++}
+Index: bigcouch-0.4.2.leap/couchjs/build/utf8.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/utf8.h 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,19 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#ifndef COUCH_JS_UTF_8_H
++#define COUCH_JS_UTF_8_H
++
++char* enc_string(JSContext* cx, jsval arg, size_t* buflen);
++JSString* dec_string(JSContext* cx, const char* buf, size_t buflen);
++
++#endif
+\ No newline at end of file
+Index: bigcouch-0.4.2.leap/couchjs/build/util.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/couchjs/build/util.h 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,33 @@
++// Licensed under the Apache License, Version 2.0 (the "License"); you may not
++// use this file except in compliance with the License. You may obtain a copy of
++// the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++// License for the specific language governing permissions and limitations under
++// the License.
++
++#ifndef COUCHJS_UTIL_H
++#define COUCHJS_UTIL_H
++
++#include "sm.h"
++
++typedef struct {
++ int use_http;
++ int stack_size;
++ const char* script_name;
++ char* script;
++} couch_args;
++
++couch_args* couch_parse_args(int argc, const char* argv[]);
++int couch_fgets(char* buf, int size, FILE* fp);
++JSString* couch_readline(JSContext* cx, FILE* fp);
++void couch_print(JSContext* cx, uintN argc, jsval* argv);
++void couch_error(JSContext* cx, const char* mesg, JSErrorReport* report);
++JSBool couch_load_funcs(JSContext* cx, JSObject* obj, JSFunctionSpec* funcs);
++
++
++#endif // Included util.h
+Index: bigcouch-0.4.2.leap/rel/dev1.config
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/rel/dev1.config 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,7 @@
++{prefix, "/root/cloudant/bigcouch-0.4.2.leap/rel/dev1"}.
++{data_dir, "/root/cloudant/bigcouch-0.4.2.leap/rel/tmpdata/dev1"}.
++{view_dir, "/root/cloudant/bigcouch-0.4.2.leap/rel/tmpdata/dev1"}.
++{node_name, "-name dev1@127.0.0.1"}.
++{cluster_port, 15984}.
++{cluster_ssl, 16984}.
++{backend_port, 15986}.
+Index: bigcouch-0.4.2.leap/rel/dev2.config
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/rel/dev2.config 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,7 @@
++{prefix, "/root/cloudant/bigcouch-0.4.2.leap/rel/dev2"}.
++{data_dir, "/root/cloudant/bigcouch-0.4.2.leap/rel/tmpdata/dev2"}.
++{view_dir, "/root/cloudant/bigcouch-0.4.2.leap/rel/tmpdata/dev2"}.
++{node_name, "-name dev2@127.0.0.1"}.
++{cluster_port, 25984}.
++{cluster_ssl, 26984}.
++{backend_port, 25986}.
+Index: bigcouch-0.4.2.leap/rel/bigcouch.config
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/rel/bigcouch.config 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,8 @@
++{prefix, "/opt/bigcouch"}.
++{data_dir, "/opt/bigcouch/var/lib"}.
++{view_dir, "/opt/bigcouch/var/lib"}.
++{user, "root"}.
++{node_name, "-name bigcouch"}.
++{cluster_port, 5984}.
++{cluster_ssl, 6984}.
++{backend_port, 5986}.
+Index: bigcouch-0.4.2.leap/rel/dev3.config
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ bigcouch-0.4.2.leap/rel/dev3.config 2014-01-17 10:53:54.345591440 -0500
+@@ -0,0 +1,7 @@
++{prefix, "/root/cloudant/bigcouch-0.4.2.leap/rel/dev3"}.
++{data_dir, "/root/cloudant/bigcouch-0.4.2.leap/rel/tmpdata/dev3"}.
++{view_dir, "/root/cloudant/bigcouch-0.4.2.leap/rel/tmpdata/dev3"}.
++{node_name, "-name dev3@127.0.0.1"}.
++{cluster_port, 35984}.
++{cluster_ssl, 36984}.
++{backend_port, 35986}.
diff --git a/debian/patches/disable_embedded_rebar b/debian/patches/disable_embedded_rebar
new file mode 100644
index 00000000..95677029
--- /dev/null
+++ b/debian/patches/disable_embedded_rebar
@@ -0,0 +1,82 @@
+Index: cloudant_bigcouch/configure
+===================================================================
+--- cloudant_bigcouch.orig/configure 2014-01-17 07:06:10.581791425 -0500
++++ cloudant_bigcouch/configure 2014-01-17 07:06:10.577791533 -0500
+@@ -88,4 +88,4 @@
+ done
+
+ mkdir -p apps/couch/ebin
+-./rebar get-deps && ./rebar update-deps && cat rel/bigcouch.config
++rebar get-deps && rebar update-deps && cat rel/bigcouch.config
+Index: cloudant_bigcouch/deps/ibrowse/Makefile
+===================================================================
+--- cloudant_bigcouch.orig/deps/ibrowse/Makefile 2014-01-17 07:06:10.581791425 -0500
++++ cloudant_bigcouch/deps/ibrowse/Makefile 2014-01-17 07:06:10.577791533 -0500
+@@ -1,17 +1,17 @@
+ IBROWSE_VSN = $(shell sed -n 's/.*{vsn,.*"\(.*\)"}.*/\1/p' src/ibrowse.app.src)
+
+ all:
+- ./rebar compile
++ rebar compile
+
+ clean:
+- ./rebar clean
++ rebar clean
+
+ install: all
+ mkdir -p $(DESTDIR)/lib/ibrowse-$(IBROWSE_VSN)/
+ cp -r ebin $(DESTDIR)/lib/ibrowse-$(IBROWSE_VSN)/
+
+ test: all
+- ./rebar eunit
++ rebar eunit
+ (cd test; make)
+ erl -noshell -pa ebin -pa test -s ibrowse -s ibrowse_test unit_tests \
+ -s ibrowse_test verify_chunked_streaming \
+Index: cloudant_bigcouch/Makefile
+===================================================================
+--- cloudant_bigcouch.orig/Makefile 2014-01-17 07:06:05.041940708 -0500
++++ cloudant_bigcouch/Makefile 2014-01-17 07:06:35.241126925 -0500
+@@ -18,23 +18,23 @@
+ compile:
+ @echo "==> couchjs (compile)"
+ @cd couchjs && python scons/scons.py
+- @./rebar compile
++ @rebar compile
+ @cat $(appfile) | sed s/%VSN%/`echo 1.1.1-792-gc8a44ff`/ > $(appfile)
+
+ clean:
+ @echo "==> couchjs (clean)"
+ @cd couchjs && python scons/scons.py --clean
+ @rm -rf couchjs/.sconf_temp couchjs/.sconsign.dblite
+- @./rebar clean
++ @rebar clean
+
+ # compile is required here because of cross-dependencies between apps
+ check: compile
+- @./rebar eunit
++ @rebar eunit
+ @ERL_FLAGS="-pa `pwd`/apps/couch/ebin" prove apps/couch/test/etap/*.t
+
+ dist: compile
+ @rm -rf rel/bigcouch
+- @./rebar generate
++ @rebar generate
+
+ distclean: clean
+ @rm -rf rel/bigcouch
+@@ -53,11 +53,11 @@
+ dev: compile
+ @rm -rf rel/dev1 rel/dev2 rel/dev3
+ @echo "==> Building development node #1 (ports 15984/15986)"
+- @./rebar generate target_dir=dev1 overlay_vars=dev1.config
++ @rebar generate target_dir=dev1 overlay_vars=dev1.config
+ @echo "==> Building development node #2 (ports 25984/25986)"
+- @./rebar generate target_dir=dev2 overlay_vars=dev2.config
++ @rebar generate target_dir=dev2 overlay_vars=dev2.config
+ @echo "==> Building development node #3 (ports 35984/35986)"
+- @./rebar generate target_dir=dev3 overlay_vars=dev3.config
++ @rebar generate target_dir=dev3 overlay_vars=dev3.config
+ @echo "\n\
+ Development nodes are built, and can be started using ./rel/dev[123]/bin/bigcouch.\n\
+ Once the nodes are started, they must be joined together by editing the local\n\
diff --git a/debian/patches/disable_embedded_scons b/debian/patches/disable_embedded_scons
new file mode 100644
index 00000000..91f57399
--- /dev/null
+++ b/debian/patches/disable_embedded_scons
@@ -0,0 +1,20 @@
+Index: cloudant_bigcouch/Makefile
+===================================================================
+--- cloudant_bigcouch.orig/Makefile 2014-01-17 07:09:37.100226333 -0500
++++ cloudant_bigcouch/Makefile 2014-01-17 07:10:27.906857239 -0500
+@@ -17,13 +17,13 @@
+ appfile = apps/couch/ebin/couch.app
+ compile:
+ @echo "==> couchjs (compile)"
+- @cd couchjs && python scons/scons.py
++ @cd couchjs && /usr/bin/scons
+ @rebar compile
+ @cat $(appfile) | sed s/%VSN%/`echo 1.1.1-792-gc8a44ff`/ > $(appfile)
+
+ clean:
+ @echo "==> couchjs (clean)"
+- @cd couchjs && python scons/scons.py --clean
++ @cd couchjs && /usr/bin/scons --clean
+ @rm -rf couchjs/.sconf_temp couchjs/.sconsign.dblite
+ @rebar clean
+
diff --git a/debian/patches/fix-body_too_large-error b/debian/patches/fix-body_too_large-error
new file mode 100644
index 00000000..2cdc03ff
--- /dev/null
+++ b/debian/patches/fix-body_too_large-error
@@ -0,0 +1,16 @@
+Index: bigcouch/deps/chttpd/src/chttpd_external.erl
+===================================================================
+--- bigcouch.orig/deps/chttpd/src/chttpd_external.erl 2014-01-15 17:02:27.578395002 +0000
++++ bigcouch/deps/chttpd/src/chttpd_external.erl 2014-01-15 17:07:01.986394813 +0000
+@@ -65,7 +65,10 @@
+ req_body=ReqBody
+ }, Db, DocId) ->
+ Body = case ReqBody of
+- undefined -> Req:recv_body();
++ undefined ->
++ MaxSize = list_to_integer(
++ couch_config:get("couchdb", "max_document_size", "4294967296")),
++ Req:recv_body(MaxSize);
+ Else -> Else
+ end,
+ ParsedForm = case Req:get_primary_header_value("content-type") of
diff --git a/debian/patches/remove_external_dependencies b/debian/patches/remove_external_dependencies
new file mode 100644
index 00000000..6ffbaeb1
--- /dev/null
+++ b/debian/patches/remove_external_dependencies
@@ -0,0 +1,32 @@
+Index: bigcouch-0.4.2.leap/rebar.config
+===================================================================
+--- bigcouch-0.4.2.leap.orig/rebar.config 2014-01-15 17:25:15.799547067 -0200
++++ bigcouch-0.4.2.leap/rebar.config 2014-01-16 13:53:31.533534156 -0200
+@@ -13,20 +13,13 @@
+ % the License.
+
+ {deps, [
+- {oauth, ".*", {git, "https://github.com/cloudant/erlang-oauth.git",
+- {tag, "BigCouch-0.4.0"}}},
+- {ibrowse, ".*", {git, "https://github.com/cloudant/ibrowse.git",
+- {tag, "CouchDB-1.1.0"}}},
+- {mochiweb, ".*", {git, "https://github.com/cloudant/mochiweb.git",
+- {tag, "CouchDB-1.1.0"}}},
+- {rexi, ".*", {git, "https://github.com/cloudant/rexi.git",
+- {tag, "1.5.5"}}},
+- {fabric, ".*", {git, "https://github.com/cloudant/fabric.git",
+- {tag, "2.0.7"}}},
+- {mem3, ".*", {git, "https://github.com/cloudant/mem3.git",
+- {tag, "2.0.0"}}},
+- {chttpd, ".*", {git, "https://github.com/cloudant/chttpd.git",
+- {tag, "1.4.3"}}}
++ oauth,
++ ibrowse,
++ mochiweb,
++ rexi,
++ fabric,
++ mem3,
++ chttpd
+ ]}.
+ % needed for a clean transition to the deps model
+ {clean_files, [
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 00000000..72c856b4
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,7 @@
+fix-body_too_large-error
+update-pthread-linking-flags
+disable_embedded_rebar
+disable_embedded_scons
+remove_external_dependencies
+support-destdir.patch
+bigcouch-configuration-changes
diff --git a/debian/patches/support-destdir.patch b/debian/patches/support-destdir.patch
new file mode 100644
index 00000000..ffea35a1
--- /dev/null
+++ b/debian/patches/support-destdir.patch
@@ -0,0 +1,25 @@
+Support $(DESTDIR) in Makefile.
+
+Index: bigcouch/Makefile
+===================================================================
+--- bigcouch.orig/Makefile 2014-01-15 16:45:52.258395008 +0000
++++ bigcouch/Makefile 2014-01-15 16:47:42.970395009 +0000
+@@ -41,14 +41,10 @@
+
+ include install.mk
+ install: dist
+- @mkdir -p $(prefix)
+- @cp -R rel/bigcouch/* $(prefix)
+- @mkdir -p $(data_dir)
+- @chown $(user) $(data_dir)
+- @mkdir -p $(view_dir)
+- @chown $(user) $(view_dir)
+- @touch $(prefix)/var/log/bigcouch.log
+- @chown $(user) $(prefix)/var/log/bigcouch.log
++ @mkdir -p $(DESTDIR)/$(prefix)
++ @cp -R rel/bigcouch/* $(DESTDIR)/$(prefix)
++ @mkdir -p $(DESTDIR)/etc/sv
++ @cp -R rel/sv/bigcouch $(DESTDIR)/etc/sv/
+
+ dev: compile
+ @rm -rf rel/dev1 rel/dev2 rel/dev3
diff --git a/debian/patches/update-pthread-linking-flags b/debian/patches/update-pthread-linking-flags
new file mode 100644
index 00000000..46faaab6
--- /dev/null
+++ b/debian/patches/update-pthread-linking-flags
@@ -0,0 +1,27 @@
+Index: cloudant_bigcouch/apps/couch/rebar.config
+===================================================================
+--- cloudant_bigcouch.orig/apps/couch/rebar.config 2014-01-17 07:02:54.167084249 -0500
++++ cloudant_bigcouch/apps/couch/rebar.config 2014-01-17 07:02:54.163084356 -0500
+@@ -1,7 +1,7 @@
+ {so_name, "couch_icu_driver.so"}.
+ {port_envs, [
+ {"DRV_CFLAGS", "$DRV_CFLAGS -DPIC -O2 -fno-common"},
+- {"DRV_LDFLAGS", "$DRV_LDFLAGS -lm -licuuc -licudata -licui18n -lpthread"},
++ {"DRV_LDFLAGS", "$DRV_LDFLAGS -lm -licuuc -licudata -licui18n -pthread"},
+ {"linux", "DRV_LDFLAGS", "$DRV_LDFLAGS -lcrypt"},
+ {"freebsd", "DRV_CFLAGS", "$DRV_CFLAGS -I/usr/local/include"},
+ {"freebsd", "DRV_LDFLAGS", "$DRV_LDFLAGS -L/usr/local/lib"},
+Index: cloudant_bigcouch/couchjs/c_src/SConscript
+===================================================================
+--- cloudant_bigcouch.orig/couchjs/c_src/SConscript 2014-01-17 07:02:54.167084249 -0500
++++ cloudant_bigcouch/couchjs/c_src/SConscript 2014-01-17 07:02:54.163084356 -0500
+@@ -23,7 +23,8 @@
+ return commands.getstatusoutput(cmd)
+
+ env = Environment(CC="c++", CCFLAGS='-g -O2 -DXP_UNIX',
+- CPPPATH=os.getenv("CPPPATH"))
++ CPPPATH=os.getenv("CPPPATH"),
++ LINKFLAGS="-pthread")
+
+ if os.uname()[0] == 'SunOS':
+ env['CC'] = '/usr/sfw/bin/gcc'
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 00000000..ac687016
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,19 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+%:
+ dh $@
+
+override_dh_auto_configure:
+ ./configure -p /opt/bigcouch
+
+override_dh_auto_test:
+ echo "skipping tests"
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 00000000..163aaf8d
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)