Return-Path: Delivered-To: apmail-couchdb-dev-archive@www.apache.org Received: (qmail 77995 invoked from network); 5 Apr 2011 15:24:12 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 5 Apr 2011 15:24:12 -0000 Received: (qmail 46766 invoked by uid 500); 5 Apr 2011 15:24:09 -0000 Delivered-To: apmail-couchdb-dev-archive@couchdb.apache.org Received: (qmail 46687 invoked by uid 500); 5 Apr 2011 15:24:09 -0000 Mailing-List: contact dev-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list dev@couchdb.apache.org Received: (qmail 46608 invoked by uid 99); 5 Apr 2011 15:24:09 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 05 Apr 2011 15:24:09 +0000 X-ASF-Spam-Status: No, hits=-0.7 required=5.0 tests=FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS,T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of fdmanana@gmail.com designates 209.85.210.52 as permitted sender) Received: from [209.85.210.52] (HELO mail-pz0-f52.google.com) (209.85.210.52) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 05 Apr 2011 15:23:57 +0000 Received: by pzk12 with SMTP id 12so317465pzk.11 for ; Tue, 05 Apr 2011 08:23:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:content-type :content-transfer-encoding; bh=1UOSFmCTFJ6Iw2NObJNVtkKNEzTdX+X7jSrV0sN4bV0=; b=RJvv9Byl83J2pv8xoW82zMxVHZBVsKlFSIgKpdbZeX8NPk1PpvQhPaY539bgfDg3NJ IGrVUdZ9LMhXOU5uG39fIvaKBzJUOZ9uI7qQP+5I1xptvlOc1xOyKuYQMBpj2J9YpCVt MQUQ7kPu7vg6fAUxNGiN+HwJ7x7+40cfc1m4U= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:content-type :content-transfer-encoding; b=cgY3r7KC/Ifq1W+G9/skQXIV/84SVjHfjZ1GSt2H4J3Rboeg//uvq+Zfk1nlux4Kbd X/pHikLqrvssq+vPW80jmK80xAgGOl5H4q1OWctFLUip7wd2huQHVWZPV4QTLAA8CTRE FbN6yxZaCxXWm+z+5qF5awf5JK0adiW6Ajsys= MIME-Version: 1.0 Received: by 10.142.250.15 with SMTP id x15mr8329109wfh.187.1302017015083; Tue, 05 Apr 2011 08:23:35 -0700 (PDT) Sender: fdmanana@gmail.com Received: by 10.68.59.164 with HTTP; Tue, 5 Apr 2011 08:23:34 -0700 (PDT) In-Reply-To: <20110405094243.410D92388A1C@eris.apache.org> References: <20110405094243.410D92388A1C@eris.apache.org> Date: Tue, 5 Apr 2011 16:23:34 +0100 X-Google-Sender-Auth: 74IhAXx4qFOzGMm7Y65pLqNhvvw Message-ID: Subject: Re: svn commit: r1088941 [1/3] - in /couchdb/trunk: ./ src/ src/couchdb/ src/ejson/ src/ejson/yajl/ test/etap/ utils/ From: Filipe David Manana To: dev@couchdb.apache.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Virus-Checked: Checked by ClamAV on apache.org This breaks 'make distcheck', sorry for the inconvenience. The error is like this: make[2]: Entering directory `/home/fdmanana/tmp/couchdb/src/ejson' make[2]: *** No rule to make target `priv', needed by `distdir'. Stop. make[2]: Leaving directory `/home/fdmanana/tmp/couchdb/src/ejson' make[1]: *** [distdir] Error 1 make[1]: Leaving directory `/home/fdmanana/tmp/couchdb/src' make: *** [distdir] Error 1 Noah, can you give me any advice about what autotools magic I need to do? I think something needs to be added to src/ejson/Makefile.am. thanks On Tue, Apr 5, 2011 at 10:42 AM, wrote: > Author: fdmanana > Date: Tue Apr =C2=A05 09:42:41 2011 > New Revision: 1088941 > > URL: http://svn.apache.org/viewvc?rev=3D1088941&view=3Drev > Log: > Added ejson application > > This is a NIF based JSON decoder/encoder based on Paul Davis' eep0018 > implementation (https://github.com/davisp/eep0018/), with some modificati= ons > from Damien (big number support and optimizations) on top, plus a few fix= es > from my side and Beno=C3=AEt on top of Damien's fork. > This module fallbacks to mochijson2 when the NIF is not loaded or compile= d. > The NIF is only compiled and used if we're using an OTP release >=3D R13B= 04. > > Thanks everyone. Closes COUCHDB-1118. > > > Added: > =C2=A0 =C2=A0couchdb/trunk/src/ejson/ > =C2=A0 =C2=A0couchdb/trunk/src/ejson/Makefile.am > =C2=A0 =C2=A0couchdb/trunk/src/ejson/decode.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/ejson.app.in > =C2=A0 =C2=A0couchdb/trunk/src/ejson/ejson.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/ejson.erl > =C2=A0 =C2=A0couchdb/trunk/src/ejson/encode.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/erl_nif_compat.h > =C2=A0 =C2=A0couchdb/trunk/src/ejson/mochijson2.erl > =C2=A0 =C2=A0couchdb/trunk/src/ejson/mochinum.erl > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/ > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_alloc.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_alloc.h > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_buf.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_buf.h > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_bytestack.h > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_common.h > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_encode.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_encode.h > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_gen.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_gen.h > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_lex.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_lex.h > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_parse.h > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_parser.c > =C2=A0 =C2=A0couchdb/trunk/src/ejson/yajl/yajl_parser.h > Modified: > =C2=A0 =C2=A0couchdb/trunk/.gitignore > =C2=A0 =C2=A0couchdb/trunk/NOTICE > =C2=A0 =C2=A0couchdb/trunk/configure.ac > =C2=A0 =C2=A0couchdb/trunk/src/Makefile.am > =C2=A0 =C2=A0couchdb/trunk/src/couchdb/couch_api_wrap.erl > =C2=A0 =C2=A0couchdb/trunk/src/couchdb/couch_db.hrl > =C2=A0 =C2=A0couchdb/trunk/src/couchdb/couch_httpd_external.erl > =C2=A0 =C2=A0couchdb/trunk/src/couchdb/couch_os_process.erl > =C2=A0 =C2=A0couchdb/trunk/src/couchdb/couch_util.erl > =C2=A0 =C2=A0couchdb/trunk/test/etap/130-attachments-md5.t > =C2=A0 =C2=A0couchdb/trunk/test/etap/140-attachment-comp.t > =C2=A0 =C2=A0couchdb/trunk/test/etap/150-invalid-view-seq.t > =C2=A0 =C2=A0couchdb/trunk/test/etap/160-vhosts.t > =C2=A0 =C2=A0couchdb/trunk/test/etap/171-os-daemons-config.es > =C2=A0 =C2=A0couchdb/trunk/test/etap/173-os-daemon-cfg-register.es > =C2=A0 =C2=A0couchdb/trunk/test/etap/test_util.erl.in > =C2=A0 =C2=A0couchdb/trunk/utils/Makefile.am > > Modified: couchdb/trunk/.gitignore > URL: http://svn.apache.org/viewvc/couchdb/trunk/.gitignore?rev=3D1088941&= r1=3D1088940&r2=3D1088941&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/.gitignore (original) > +++ couchdb/trunk/.gitignore Tue Apr =C2=A05 09:42:41 2011 > @@ -64,6 +64,10 @@ src/couchdb/priv/couchspawnkillable > =C2=A0src/couchdb/priv/stat_descriptions.cfg > =C2=A0src/erlang-oauth/oauth.app > =C2=A0src/ibrowse/ibrowse.app > +src/ejson/ejson.app > +src/ejson/.deps/ > +src/ejson/.libs/ > +src/ejson/priv > =C2=A0src/mochiweb/mochiweb.app > =C2=A0test/local.ini > =C2=A0test/etap/run > > Modified: couchdb/trunk/NOTICE > URL: http://svn.apache.org/viewvc/couchdb/trunk/NOTICE?rev=3D1088941&r1= =3D1088940&r2=3D1088941&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/NOTICE (original) > +++ couchdb/trunk/NOTICE Tue Apr =C2=A05 09:42:41 2011 > @@ -49,3 +49,13 @@ This product also includes the following > =C2=A0* jspec.js (http://visionmedia.github.com/jspec/) > > =C2=A0 Copyright 2010 TJ Holowaychuk > + > + * yajl (http://lloyd.github.com/yajl/) > + > + =C2=A0Copyright 2010, Lloyd Hilaiel > + > + * ejson > + > + =C2=A0Based on Paul Davis' eep0018 implementation (https://github.com/d= avisp/eep0018/), > + =C2=A0with some modifications from Damien Katz, Filipe Manana and Beno= =C3=83=C2=AEt Chesneau. > + =C2=A0This application uses yajl. > \ No newline at end of file > > Modified: couchdb/trunk/configure.ac > URL: http://svn.apache.org/viewvc/couchdb/trunk/configure.ac?rev=3D108894= 1&r1=3D1088940&r2=3D1088941&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/configure.ac (original) > +++ couchdb/trunk/configure.ac Tue Apr =C2=A05 09:42:41 2011 > @@ -262,6 +262,10 @@ if test `echo $version | ${AWK} "{print > =C2=A0 =C2=A0 fi > =C2=A0fi > > +otp_release=3D"`${ERL} -noshell -eval 'io:put_chars(erlang:system_info(o= tp_release)).' -s erlang halt`" > +AC_SUBST(otp_release) > +AM_CONDITIONAL([USE_OTP_NIFS], [test x$otp_release \> xR13B03]) > + > =C2=A0has_crypto=3D`${ERL} -eval "case application:load(crypto) of ok -> = ok; _ -> exit(no_crypto) end." -noshell -s init stop` > > =C2=A0if test -n "$has_crypto"; then > @@ -419,6 +423,7 @@ AC_CONFIG_FILES([src/erlang-oauth/Makefi > =C2=A0AC_CONFIG_FILES([src/etap/Makefile]) > =C2=A0AC_CONFIG_FILES([src/ibrowse/Makefile]) > =C2=A0AC_CONFIG_FILES([src/mochiweb/Makefile]) > +AC_CONFIG_FILES([src/ejson/Makefile]) > =C2=A0AC_CONFIG_FILES([test/Makefile]) > =C2=A0AC_CONFIG_FILES([test/bench/Makefile]) > =C2=A0AC_CONFIG_FILES([test/etap/Makefile]) > > Modified: couchdb/trunk/src/Makefile.am > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/Makefile.am?rev=3D108= 8941&r1=3D1088940&r2=3D1088941&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/Makefile.am (original) > +++ couchdb/trunk/src/Makefile.am Tue Apr =C2=A05 09:42:41 2011 > @@ -10,4 +10,4 @@ > =C2=A0## License for the specific language governing permissions and limi= tations under > =C2=A0## the License. > > -SUBDIRS =3D couchdb erlang-oauth etap ibrowse mochiweb > +SUBDIRS =3D couchdb erlang-oauth etap ibrowse mochiweb ejson > > Modified: couchdb/trunk/src/couchdb/couch_api_wrap.erl > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_api_wra= p.erl?rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/couchdb/couch_api_wrap.erl (original) > +++ couchdb/trunk/src/couchdb/couch_api_wrap.erl Tue Apr =C2=A05 09:42:41= 2011 > @@ -427,7 +427,7 @@ options_to_query_args([revs | Rest], Acc > =C2=A0options_to_query_args([{open_revs, all} | Rest], Acc) -> > =C2=A0 =C2=A0 options_to_query_args(Rest, [{"open_revs", "all"} | Acc]); > =C2=A0options_to_query_args([{open_revs, Revs} | Rest], Acc) -> > - =C2=A0 =C2=A0JsonRevs =3D ?JSON_ENCODE(couch_doc:revs_to_strs(Revs)), > + =C2=A0 =C2=A0JsonRevs =3D ?b2l(?JSON_ENCODE(couch_doc:revs_to_strs(Revs= ))), > =C2=A0 =C2=A0 options_to_query_args(Rest, [{"open_revs", JsonRevs} | Acc]= ). > > > > Modified: couchdb/trunk/src/couchdb/couch_db.hrl > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_db.hrl?= rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/couchdb/couch_db.hrl (original) > +++ couchdb/trunk/src/couchdb/couch_db.hrl Tue Apr =C2=A05 09:42:41 2011 > @@ -20,8 +20,8 @@ > =C2=A0% the lowest possible database sequence number > =C2=A0-define(LOWEST_SEQ, 0). > > --define(JSON_ENCODE(V), couch_util:json_encode(V)). > --define(JSON_DECODE(V), couch_util:json_decode(V)). > +-define(JSON_ENCODE(V), ejson:encode(V)). > +-define(JSON_DECODE(V), ejson:decode(V)). > > =C2=A0-define(b2l(V), binary_to_list(V)). > =C2=A0-define(l2b(V), list_to_binary(V)). > > Modified: couchdb/trunk/src/couchdb/couch_httpd_external.erl > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_e= xternal.erl?rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/couchdb/couch_httpd_external.erl (original) > +++ couchdb/trunk/src/couchdb/couch_httpd_external.erl Tue Apr =C2=A05 09= :42:41 2011 > @@ -105,11 +105,11 @@ json_query_keys({Json}) -> > =C2=A0json_query_keys([], Acc) -> > =C2=A0 =C2=A0 {lists:reverse(Acc)}; > =C2=A0json_query_keys([{<<"startkey">>, Value} | Rest], Acc) -> > - =C2=A0 =C2=A0json_query_keys(Rest, [{<<"startkey">>, couch_util:json_de= code(Value)}|Acc]); > + =C2=A0 =C2=A0json_query_keys(Rest, [{<<"startkey">>, ?JSON_DECODE(Value= )}|Acc]); > =C2=A0json_query_keys([{<<"endkey">>, Value} | Rest], Acc) -> > - =C2=A0 =C2=A0json_query_keys(Rest, [{<<"endkey">>, couch_util:json_deco= de(Value)}|Acc]); > + =C2=A0 =C2=A0json_query_keys(Rest, [{<<"endkey">>, ?JSON_DECODE(Value)}= |Acc]); > =C2=A0json_query_keys([{<<"key">>, Value} | Rest], Acc) -> > - =C2=A0 =C2=A0json_query_keys(Rest, [{<<"key">>, couch_util:json_decode(= Value)}|Acc]); > + =C2=A0 =C2=A0json_query_keys(Rest, [{<<"key">>, ?JSON_DECODE(Value)}|Ac= c]); > =C2=A0json_query_keys([Term | Rest], Acc) -> > =C2=A0 =C2=A0 json_query_keys(Rest, [Term|Acc]). > > > Modified: couchdb/trunk/src/couchdb/couch_os_process.erl > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_os_proc= ess.erl?rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/couchdb/couch_os_process.erl (original) > +++ couchdb/trunk/src/couchdb/couch_os_process.erl Tue Apr =C2=A05 09:42:= 41 2011 > @@ -60,7 +60,7 @@ prompt(Pid, Data) -> > =C2=A0% Utility functions for reading and writing > =C2=A0% in custom functions > =C2=A0writeline(OsProc, Data) when is_record(OsProc, os_proc) -> > - =C2=A0 =C2=A0port_command(OsProc#os_proc.port, Data ++ "\n"). > + =C2=A0 =C2=A0port_command(OsProc#os_proc.port, [Data, $\n]). > > =C2=A0readline(#os_proc{} =3D OsProc) -> > =C2=A0 =C2=A0 readline(OsProc, []). > > Modified: couchdb/trunk/src/couchdb/couch_util.erl > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_util.er= l?rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/couchdb/couch_util.erl (original) > +++ couchdb/trunk/src/couchdb/couch_util.erl Tue Apr =C2=A05 09:42:41 201= 1 > @@ -21,7 +21,6 @@ > =C2=A0-export([get_nested_json_value/2, json_user_ctx/1]). > =C2=A0-export([proplist_apply_field/2, json_apply_field/2]). > =C2=A0-export([to_binary/1, to_integer/1, to_list/1, url_encode/1]). > --export([json_encode/1, json_decode/1]). > =C2=A0-export([verify/2,simple_call/2,shutdown_sync/1]). > =C2=A0-export([get_value/2, get_value/3]). > =C2=A0-export([md5/1, md5_init/0, md5_update/2, md5_final/1]). > @@ -374,22 +373,6 @@ url_encode([H|T]) -> > =C2=A0url_encode([]) -> > =C2=A0 =C2=A0 []. > > -json_encode(V) -> > - =C2=A0 =C2=A0Handler =3D > - =C2=A0 =C2=A0fun({L}) when is_list(L) -> > - =C2=A0 =C2=A0 =C2=A0 =C2=A0{struct,L}; > - =C2=A0 =C2=A0(Bad) -> > - =C2=A0 =C2=A0 =C2=A0 =C2=A0exit({json_encode, {bad_term, Bad}}) > - =C2=A0 =C2=A0end, > - =C2=A0 =C2=A0(mochijson2:encoder([{handler, Handler}]))(V). > - > -json_decode(V) -> > - =C2=A0 =C2=A0try (mochijson2:decoder([{object_hook, fun({struct,L}) -> = {L} end}]))(V) > - =C2=A0 =C2=A0catch > - =C2=A0 =C2=A0 =C2=A0 =C2=A0_Type:_Error -> > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0throw({invalid_json,V}) > - =C2=A0 =C2=A0end. > - > =C2=A0verify([X|RestX], [Y|RestY], Result) -> > =C2=A0 =C2=A0 verify(RestX, RestY, (X bxor Y) bor Result); > =C2=A0verify([], [], Result) -> > > Added: couchdb/trunk/src/ejson/Makefile.am > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/Makefile.am?rev= =3D1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/Makefile.am (added) > +++ couchdb/trunk/src/ejson/Makefile.am Tue Apr =C2=A05 09:42:41 2011 > @@ -0,0 +1,86 @@ > +## Licensed under the Apache License, Version 2.0 (the "License"); you m= ay not > +## use this file except in compliance with the License. You may obtain a= copy of > +## the License at > +## > +## =C2=A0 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, WIT= HOUT > +## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See = the > +## License for the specific language governing permissions and limitatio= ns under > +## the License. > + > +ejsonebindir =3D $(localerlanglibdir)/ejson-0.1.0/ebin > +ejsonprivdir =3D $(localerlanglibdir)/ejson-0.1.0/priv > + > +CLEANFILES =3D \ > + =C2=A0 =C2=A0$(ejsonebin_make_generated_file_list) \ > + =C2=A0 =C2=A0$(ejsonpriv_make_generated_file_list) > + > +if USE_OTP_NIFS > +ejsonpriv_LTLIBRARIES =3D ejson.la > +endif > + > +EJSON_C_SRCS =3D \ > + =C2=A0 =C2=A0 =C2=A0 ejson.c \ > + =C2=A0 =C2=A0 =C2=A0 decode.c \ > + =C2=A0 =C2=A0 =C2=A0 encode.c \ > + =C2=A0 =C2=A0 =C2=A0 yajl/yajl_alloc.c \ > + =C2=A0 =C2=A0 =C2=A0 yajl/yajl_buf.c \ > + =C2=A0 =C2=A0 =C2=A0 yajl/yajl.c \ > + =C2=A0 =C2=A0 =C2=A0 yajl/yajl_encode.c \ > + =C2=A0 =C2=A0 =C2=A0 yajl/yajl_gen.c \ > + =C2=A0 =C2=A0 =C2=A0 yajl/yajl_lex.c \ > + =C2=A0 =C2=A0 =C2=A0 yajl/yajl_parser.c > + > +if USE_OTP_NIFS > +ejson_la_SOURCES =3D $(EJSON_C_SRCS) > +ejson_la_LDFLAGS =3D -module -avoid-version > + > +if WINDOWS > +ejson_la_LDFLAGS +=3D -no-undefined > +endif > +endif > + > +ejson_file_collection =3D \ > + =C2=A0 =C2=A0ejson.app.in \ > + =C2=A0 =C2=A0ejson.erl \ > + =C2=A0 =C2=A0mochijson2.erl \ > + =C2=A0 =C2=A0mochinum.erl \ > + =C2=A0 =C2=A0$(JSON_C_SRCS) > + > +ejsonebin_make_generated_file_list =3D \ > + =C2=A0 =C2=A0ejson.app \ > + =C2=A0 =C2=A0ejson.beam \ > + =C2=A0 =C2=A0mochijson2.beam \ > + =C2=A0 =C2=A0mochinum.beam > + > +ejsonebin_DATA =3D \ > + =C2=A0 =C2=A0$(ejsonebin_make_generated_file_list) > + > +EXTRA_DIST =3D =C2=A0\ > + =C2=A0 =C2=A0$(ejson_file_collection) \ > + =C2=A0 =C2=A0erl_nif_compat.h \ > + =C2=A0 =C2=A0yajl/yajl_alloc.h \ > + =C2=A0 =C2=A0yajl/yajl_buf.h \ > + =C2=A0 =C2=A0yajl/yajl_bytestack.h \ > + =C2=A0 =C2=A0yajl/yajl_common.h \ > + =C2=A0 =C2=A0yajl/yajl_encode.h \ > + =C2=A0 =C2=A0yajl/yajl_gen.h \ > + =C2=A0 =C2=A0yajl/yajl_lex.h \ > + =C2=A0 =C2=A0yajl/yajl_parse.h \ > + =C2=A0 =C2=A0yajl/yajl_parser.h \ > + =C2=A0 =C2=A0priv > + > +if USE_OTP_NIFS > +priv/ejson.so: .libs/ejson.so > + =C2=A0 =C2=A0 =C2=A0 $(LN_S) .libs priv > + > +all: priv/ejson.so > +endif > + > +%.app: %.app.in > + =C2=A0 =C2=A0 =C2=A0 cp $< $@ > + > +%.beam: %.erl > + =C2=A0 =C2=A0 =C2=A0 $(ERLC) $(ERLC_FLAGS) $< > > Added: couchdb/trunk/src/ejson/decode.c > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/decode.c?rev=3D= 1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/decode.c (added) > +++ couchdb/trunk/src/ejson/decode.c Tue Apr =C2=A05 09:42:41 2011 > @@ -0,0 +1,296 @@ > +#include > +#include > +#include > + > +#include "erl_nif.h" > +#include "erl_nif_compat.h" > +#include "yajl/yajl_parse.h" > +#include "yajl/yajl_parser.h" > +#include "yajl/yajl_lex.h" > + > +typedef struct { > + =C2=A0 =C2=A0ERL_NIF_TERM head; > + =C2=A0 =C2=A0ErlNifEnv* env; > +} decode_ctx; > + > +#define ENV(ctxarg) (((decode_ctx*)ctxarg)->env) > + > +#define CONTINUE 1 > +#define CANCEL 0 > + > + > +static ERL_NIF_TERM > +make_error(yajl_handle handle, ErlNifEnv* env) > +{ > + =C2=A0 =C2=A0char* yajlError =3D (char*) yajl_get_error(handle, 0, NULL= , 0); > + =C2=A0 =C2=A0ERL_NIF_TERM errMsg; > + > + =C2=A0 =C2=A0if(yajlError !=3D NULL) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0errMsg =3D enif_make_string(env, yajlError, = ERL_NIF_LATIN1); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0yajl_free_error(handle, (unsigned char*) yaj= lError); > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0else > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0errMsg =3D enif_make_string(env, "unknown pa= rse error", ERL_NIF_LATIN1); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0return enif_make_tuple(env, 2, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(env, "error"), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_tuple(env, 2, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_uint(env, handle->by= tesConsumed), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0errMsg > + =C2=A0 =C2=A0 =C2=A0 =C2=A0) > + =C2=A0 =C2=A0); > +} > + > + > +static void > +add_to_head(void* vctx, ERL_NIF_TERM newhead) > +{ > + =C2=A0 =C2=A0decode_ctx* ctx =3D (decode_ctx*)vctx; > + =C2=A0 =C2=A0ctx->head =3D enif_make_list_cell(ctx->env, newhead, ctx->= head); > +} > + > +static int > +decode_null(void* ctx) > +{ > + =C2=A0 =C2=A0add_to_head(ctx, enif_make_atom(ENV(ctx), "null")); > + =C2=A0 =C2=A0return CONTINUE; > +} > + > +static int > +decode_boolean(void* ctx, int val) > +{ > + =C2=A0 =C2=A0add_to_head(ctx, enif_make_atom(ENV(ctx), val ? "true" : "= false")); > + =C2=A0 =C2=A0return CONTINUE; > +} > + > +static int > +decode_number(void * ctx, const char * numberVal, unsigned int numberLen= ) > +{ > + =C2=A0 =C2=A0// scan in the input to see if it's a float or int > + > + =C2=A0 =C2=A0int numberType =3D 0; // 0 means integer, 1 means float > + =C2=A0 =C2=A0unsigned int i; > + =C2=A0 =C2=A0ErlNifBinary bin; > + =C2=A0 =C2=A0int missingDot =3D 1; > + =C2=A0 =C2=A0unsigned int expPos; > + > + =C2=A0 =C2=A0for(i=3D0; i + =C2=A0 =C2=A0 =C2=A0 =C2=A0switch (numberVal[i]) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case '.': > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0missingDot =3D 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0numberType =3D 1; // it's =C2= =A0a float > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto loopend; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'E': > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'e': > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0expPos =3D i; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0numberType =3D 1; // it's =C2= =A0a float > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto loopend; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > +loopend: > + =C2=A0 =C2=A0if ((numberType =3D=3D 1) && missingDot) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if(!enif_alloc_binary_compat(ENV(ctx), numbe= rLen + 2, &bin)) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return CANCEL; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0memcpy(bin.data, numberVal, expPos); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bin.data[expPos] =3D '.'; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bin.data[expPos + 1] =3D '0'; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0memcpy(bin.data + expPos + 2, numberVal + ex= pPos, numberLen - expPos); > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0else > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if(!enif_alloc_binary_compat(ENV(ctx), numbe= rLen, &bin)) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return CANCEL; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0memcpy(bin.data, numberVal, numberLen); > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0add_to_head(ctx, enif_make_tuple(ENV(ctx), 2, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0enif_make_int(ENV(ctx), numberType), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0enif_make_binary(ENV(ctx), &bin))); > + =C2=A0 =C2=A0return CONTINUE; > +} > + > + > + > +static int > +decode_string(void* ctx, const unsigned char* data, unsigned int size) > +{ > + =C2=A0 =C2=A0ErlNifBinary bin; > + =C2=A0 =C2=A0if(!enif_alloc_binary_compat(ENV(ctx), size, &bin)) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return CANCEL; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0memcpy(bin.data, data, size); > + =C2=A0 =C2=A0add_to_head(ctx, enif_make_binary(ENV(ctx), &bin)); > + =C2=A0 =C2=A0return CONTINUE; > +} > + > +static int > +decode_start_array(void* ctx) > +{ > + =C2=A0 =C2=A0add_to_head(ctx, enif_make_int(ENV(ctx), 0)); > + =C2=A0 =C2=A0return CONTINUE; > +} > + > + > +static int > +decode_end_array(void* ctx) > +{ > + =C2=A0 =C2=A0add_to_head(ctx, enif_make_int(ENV(ctx), 1)); > + =C2=A0 =C2=A0return CONTINUE; > +} > + > + > +static int > +decode_start_map(void* ctx) > +{ > + =C2=A0 =C2=A0add_to_head(ctx, enif_make_int(ENV(ctx), 2)); > + =C2=A0 =C2=A0return CONTINUE; > +} > + > + > +static int > +decode_end_map(void* ctx) > +{ > + =C2=A0 =C2=A0add_to_head(ctx, enif_make_int(ENV(ctx), 3)); > + =C2=A0 =C2=A0return CONTINUE; > +} > + > + > +static int > +decode_map_key(void* ctx, const unsigned char* data, unsigned int size) > +{ > + =C2=A0 =C2=A0ErlNifBinary bin; > + =C2=A0 =C2=A0if(!enif_alloc_binary_compat(ENV(ctx), size, &bin)) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 return CANCEL; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0memcpy(bin.data, data, size); > + =C2=A0 =C2=A0add_to_head(ctx, enif_make_tuple(ENV(ctx), 2, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0enif_make_int(ENV(ctx), 3), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0enif_make_binary(ENV(ctx), &bin))); > + =C2=A0 =C2=A0return CONTINUE; > +} > + > +static yajl_callbacks > +decoder_callbacks =3D { > + =C2=A0 =C2=A0decode_null, > + =C2=A0 =C2=A0decode_boolean, > + =C2=A0 =C2=A0NULL, > + =C2=A0 =C2=A0NULL, > + =C2=A0 =C2=A0decode_number, > + =C2=A0 =C2=A0decode_string, > + =C2=A0 =C2=A0decode_start_map, > + =C2=A0 =C2=A0decode_map_key, > + =C2=A0 =C2=A0decode_end_map, > + =C2=A0 =C2=A0decode_start_array, > + =C2=A0 =C2=A0decode_end_array > +}; > + > +static int > +check_rest(unsigned char* data, unsigned int size, unsigned int used) > +{ > + =C2=A0 =C2=A0unsigned int i =3D 0; > + =C2=A0 =C2=A0for(i =3D used; i < size; i++) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0switch(data[i]) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case ' ': > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case '\t': > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case '\r': > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case '\n': > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0continue; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return CANCEL; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0return CONTINUE; > +} > + > +ERL_NIF_TERM > +reverse_tokens(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) > +{ > + =C2=A0 =C2=A0decode_ctx ctx; > + =C2=A0 =C2=A0yajl_parser_config conf =3D {0, 1}; // No comments, check = utf8 > + =C2=A0 =C2=A0yajl_handle handle =3D yajl_alloc(&decoder_callbacks, &con= f, NULL, &ctx); > + =C2=A0 =C2=A0yajl_status status; > + =C2=A0 =C2=A0unsigned int used; > + =C2=A0 =C2=A0ErlNifBinary bin; > + =C2=A0 =C2=A0ERL_NIF_TERM ret; > + > + =C2=A0 =C2=A0ctx.env =3D env; > + =C2=A0 =C2=A0ctx.head =3D enif_make_list_from_array(env, NULL, 0); > + > + =C2=A0 =C2=A0if(!enif_inspect_iolist_as_binary(env, argv[0], &bin)) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D enif_make_badarg(env); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0status =3D yajl_parse(handle, bin.data, bin.size); > + =C2=A0 =C2=A0used =3D handle->bytesConsumed; > + > + =C2=A0 =C2=A0// Parsing something like "2.0" (without quotes) will > + =C2=A0 =C2=A0// cause a spurious semi-error. We add the extra size > + =C2=A0 =C2=A0// check so that "2008-20-10" doesn't pass. > + =C2=A0 =C2=A0if(status =3D=3D yajl_status_insufficient_data && used =3D= =3D bin.size) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0status =3D yajl_parse_complete(handle); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0if(status =3D=3D yajl_status_ok && used !=3D bin.size) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if(check_rest(bin.data, bin.size, used) =3D= =3D CANCEL) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D enif_make_tuple(env, 2= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(e= nv, "error"), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(e= nv, "garbage_after_value") > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0switch(status) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case yajl_status_ok: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D enif_make_tuple(env, 2= , enif_make_atom(env, "ok"), ctx.head); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case yajl_status_error: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D make_error(handle, env= ); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case yajl_status_insufficient_data: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D enif_make_tuple(env, 2= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(e= nv, "error"), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(e= nv, "insufficient_data") > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case yajl_status_client_canceled: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* the only time we do this is when we can't= allocate a binary. */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D enif_make_tuple(env, 2= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(e= nv, "error"), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(e= nv, "insufficient_memory") > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D enif_make_tuple(env, 2= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(e= nv, "error"), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(e= nv, "unknown") > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + =C2=A0 =C2=A0} > + > +done: > + =C2=A0 =C2=A0if(handle !=3D NULL) yajl_free(handle); > + =C2=A0 =C2=A0return ret; > +} > > Added: couchdb/trunk/src/ejson/ejson.app.in > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/ejson.app.in?re= v=3D1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/ejson.app.in (added) > +++ couchdb/trunk/src/ejson/ejson.app.in Tue Apr =C2=A05 09:42:41 2011 > @@ -0,0 +1,9 @@ > +{application, ejson, [ > + =C2=A0 =C2=A0{description, "EJSON - decode and encode JSON into/from Er= lang terms"}, > + =C2=A0 =C2=A0{vsn, "0.1.0"}, > + =C2=A0 =C2=A0{modules, [ejson]}, > + =C2=A0 =C2=A0{registered, []}, > + =C2=A0 =C2=A0{applications, [kernel, stdlib]}, > + =C2=A0 =C2=A0{env, []} > +]}. > + > > Added: couchdb/trunk/src/ejson/ejson.c > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/ejson.c?rev=3D1= 088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/ejson.c (added) > +++ couchdb/trunk/src/ejson/ejson.c Tue Apr =C2=A05 09:42:41 2011 > @@ -0,0 +1,30 @@ > +#include "erl_nif.h" > + > +ERL_NIF_TERM final_encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM a= rgv[]); > +ERL_NIF_TERM reverse_tokens(ErlNifEnv* env, int argc, const ERL_NIF_TERM= argv[]); > + > +int > +on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM info) > +{ > + =C2=A0 =C2=A0return 0; > +} > + > +int > +on_reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM info) > +{ > + =C2=A0 =C2=A0return 0; > +} > + > +int > +on_upgrade(ErlNifEnv* env, void** priv_data, void** old_data, ERL_NIF_TE= RM info) > +{ > + =C2=A0 =C2=A0return 0; > +} > + > +static ErlNifFunc nif_funcs[] =3D > +{ > + =C2=A0 =C2=A0{"final_encode", 1, final_encode}, > + =C2=A0 =C2=A0{"reverse_tokens", 1, reverse_tokens} > +}; > + > +ERL_NIF_INIT(ejson, nif_funcs, &on_load, &on_reload, &on_upgrade, NULL); > > Added: couchdb/trunk/src/ejson/ejson.erl > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/ejson.erl?rev= =3D1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/ejson.erl (added) > +++ couchdb/trunk/src/ejson/ejson.erl Tue Apr =C2=A05 09:42:41 2011 > @@ -0,0 +1,151 @@ > +-module(ejson). > +-export([encode/1, decode/1]). > +-on_load(init/0). > + > +init() -> > + =C2=A0 =C2=A0SoName =3D case code:priv_dir(ejson) of > + =C2=A0 =C2=A0{error, bad_name} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case filelib:is_dir(filename:join(["..", pri= v])) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0filename:join(["..", priv, ejs= on]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0filename:join([priv, ejson]) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0end; > + =C2=A0 =C2=A0Dir -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0filename:join(Dir, ejson) > + =C2=A0 =C2=A0end, > + =C2=A0 =C2=A0(catch erlang:load_nif(SoName, 0)), > + =C2=A0 =C2=A0ok. > + > + > +decode(IoList) -> > + =C2=A0 =C2=A0try > + =C2=A0 =C2=A0 =C2=A0 =C2=A0nif_decode(IoList) > + =C2=A0 =C2=A0catch exit:ejson_nif_not_loaded -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0erl_decode(IoList) > + =C2=A0 =C2=A0end. > + > +encode(EJson) -> > + =C2=A0 =C2=A0try > + =C2=A0 =C2=A0 =C2=A0 =C2=A0nif_encode(EJson) > + =C2=A0 =C2=A0catch exit:ejson_nif_not_loaded -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0erl_encode(EJson) > + =C2=A0 =C2=A0end. > + > + > +nif_decode(IoList) -> > + =C2=A0 =C2=A0case reverse_tokens(IoList) of > + =C2=A0 =C2=A0{ok, ReverseTokens} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0[[EJson]] =3D make_ejson(ReverseTokens, [[]]= ), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0EJson; > + =C2=A0 =C2=A0Error -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0throw({invalid_json, {Error, IoList}}) > + =C2=A0 =C2=A0end. > + > + > +erl_decode(IoList) -> > + =C2=A0 =C2=A0try > + =C2=A0 =C2=A0 =C2=A0 =C2=A0(mochijson2:decoder([{object_hook, fun({stru= ct, L}) -> {L} end}]))(IoList) > + =C2=A0 =C2=A0catch _Type:Error -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0throw({invalid_json, {Error, IoList}}) > + =C2=A0 =C2=A0end. > + > + > +nif_encode(EJson) -> > + =C2=A0 =C2=A0RevList =3D encode_rev(EJson), > + =C2=A0 =C2=A0final_encode(lists:reverse(lists:flatten([RevList]))). > + > + > +erl_encode(EJson) -> > + =C2=A0 =C2=A0Opts =3D [{handler, fun mochi_encode_handler/1}], > + =C2=A0 =C2=A0iolist_to_binary((mochijson2:encoder(Opts))(EJson)). > + > +mochi_encode_handler({L}) when is_list(L) -> > + =C2=A0 =C2=A0{struct, L}; > +mochi_encode_handler(Bad) -> > + =C2=A0 =C2=A0exit({json_encode, {bad_term, Bad}}). > + > + > +% Encode the json into a reverse list that's almost an iolist > +% everything in the list is the final output except for tuples with > +% {0, Strings} and {1, Floats}, which are to be converted to strings > +% inside the NIF. > +encode_rev(true) -> > + =C2=A0 =C2=A0<<"true">>; > +encode_rev(false) -> > + =C2=A0 =C2=A0<<"false">>; > +encode_rev(null) -> > + =C2=A0 =C2=A0<<"null">>; > +encode_rev(I) when is_integer(I) -> > + =C2=A0 =C2=A0list_to_binary(integer_to_list(I)); > +encode_rev(S) when is_binary(S) -> > + =C2=A0 =C2=A0{0, S}; > +encode_rev(S) when is_atom(S) -> > + =C2=A0 =C2=A0{0, list_to_binary(atom_to_list(S))}; > +encode_rev(F) when is_float(F) -> > + =C2=A0 =C2=A0{1, F}; > +encode_rev({Props}) when is_list(Props) -> > + =C2=A0 =C2=A0encode_proplist_rev(Props, [<<"{">>]); > +encode_rev(Array) when is_list(Array) -> > + =C2=A0 =C2=A0encode_array_rev(Array, [<<"[">>]); > +encode_rev(Bad) -> > + =C2=A0 =C2=A0throw({json_encode, {bad_term, Bad}}). > + > + > +encode_array_rev([], Acc) -> > + =C2=A0 =C2=A0[<<"]">> | Acc]; > +encode_array_rev([Val | Rest], [<<"[">>]) -> > + =C2=A0 =C2=A0encode_array_rev(Rest, [encode_rev(Val), <<"[">>]); > +encode_array_rev([Val | Rest], Acc) -> > + =C2=A0 =C2=A0encode_array_rev(Rest, [encode_rev(Val), <<",">> | Acc]). > + > + > +encode_proplist_rev([], Acc) -> > + =C2=A0 =C2=A0[<<"}">> | Acc]; > +encode_proplist_rev([{Key,Val} | Rest], [<<"{">>]) -> > + =C2=A0 =C2=A0encode_proplist_rev( > + =C2=A0 =C2=A0 =C2=A0 =C2=A0Rest, [encode_rev(Val), <<":">>, {0, as_bina= ry(Key)}, <<"{">>]); > +encode_proplist_rev([{Key,Val} | Rest], Acc) -> > + =C2=A0 =C2=A0encode_proplist_rev( > + =C2=A0 =C2=A0 =C2=A0 =C2=A0Rest, [encode_rev(Val), <<":">>, {0, as_bina= ry(Key)}, <<",">> | Acc]). > + > +as_binary(B) when is_binary(B) -> > + =C2=A0 =C2=A0B; > +as_binary(A) when is_atom(A) -> > + =C2=A0 =C2=A0list_to_binary(atom_to_list(A)); > +as_binary(L) when is_list(L) -> > + =C2=A0 =C2=A0list_to_binary(L). > + > + > +make_ejson([], Stack) -> > + =C2=A0 =C2=A0Stack; > +make_ejson([0 | RevEvs], [ArrayValues, PrevValues | RestStack]) -> > + =C2=A0 =C2=A0% 0 ArrayStart > + =C2=A0 =C2=A0make_ejson(RevEvs, [[ArrayValues | PrevValues] | RestStack= ]); > +make_ejson([1 | RevEvs], Stack) -> > + =C2=A0 =C2=A0% 1 ArrayEnd > + =C2=A0 =C2=A0make_ejson(RevEvs, [[] | Stack]); > +make_ejson([2 | RevEvs], [ObjValues, PrevValues | RestStack]) -> > + =C2=A0 =C2=A0% 2 ObjectStart > + =C2=A0 =C2=A0make_ejson(RevEvs, [[{ObjValues} | PrevValues] | RestStack= ]); > +make_ejson([3 | RevEvs], Stack) -> > + =C2=A0 =C2=A0% 3 ObjectEnd > + =C2=A0 =C2=A0make_ejson(RevEvs, [[] | Stack]); > +make_ejson([{0, Value} | RevEvs], [Vals | RestStack] =3D _Stack) -> > + =C2=A0 =C2=A0% {0, IntegerString} > + =C2=A0 =C2=A0make_ejson(RevEvs, [[list_to_integer(binary_to_list(Value)= ) | Vals] | RestStack]); > +make_ejson([{1, Value} | RevEvs], [Vals | RestStack] =3D _Stack) -> > + =C2=A0 =C2=A0% {1, FloatString} > + =C2=A0 =C2=A0make_ejson(RevEvs, [[list_to_float(binary_to_list(Value)) = | Vals] | RestStack]); > +make_ejson([{3, String} | RevEvs], [[PrevValue|RestObject] | RestStack] = =3D _Stack) -> > + =C2=A0 =C2=A0% {3 , ObjectKey} > + =C2=A0 =C2=A0make_ejson(RevEvs, [[{String, PrevValue}|RestObject] | Res= tStack]); > +make_ejson([Value | RevEvs], [Vals | RestStack] =3D _Stack) -> > + =C2=A0 =C2=A0make_ejson(RevEvs, [[Value | Vals] | RestStack]). > + > + > +reverse_tokens(_) -> > + =C2=A0 =C2=A0exit(ejson_nif_not_loaded). > + > +final_encode(_) -> > + =C2=A0 =C2=A0exit(ejson_nif_not_loaded). > > Added: couchdb/trunk/src/ejson/encode.c > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/encode.c?rev=3D= 1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/encode.c (added) > +++ couchdb/trunk/src/ejson/encode.c Tue Apr =C2=A05 09:42:41 2011 > @@ -0,0 +1,164 @@ > +#include > +#include > +#include > + > +#include "erl_nif.h" > +#include "erl_nif_compat.h" > +#include "yajl/yajl_encode.h" > + > +#define SUCCESS 0 > +#define NOMEM 1 > +#define BADARG 2 > + > + > +typedef struct { > + =C2=A0 =C2=A0ErlNifEnv* env; > + =C2=A0 =C2=A0ErlNifBinary bin; > + =C2=A0 =C2=A0size_t fill_offset; > + =C2=A0 =C2=A0int error; > +} encode_ctx; > + > + > +static int > +ensure_buffer(void* vctx, unsigned int len) { > + =C2=A0 =C2=A0encode_ctx* ctx =3D (encode_ctx*)vctx; > + =C2=A0 =C2=A0if ((ctx->bin.size - ctx->fill_offset) < len) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if(!enif_realloc_binary_compat(ctx->env, &(c= tx->bin), (ctx->bin.size * 2) + len)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return NOMEM; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0return SUCCESS; > +} > + > +static void > +fill_buffer(void* vctx, const char* str, unsigned int len) > +{ > + =C2=A0 =C2=A0encode_ctx* ctx =3D (encode_ctx*)vctx; > + > + =C2=A0 =C2=A0if (ctx->error || (ctx->error =3D ensure_buffer(vctx, len)= )) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0memcpy(ctx->bin.data + ctx->fill_offset, str, len); > + =C2=A0 =C2=A0ctx->fill_offset +=3D len; > +} > + > +/* Json encode the string binary into the ctx.bin, > + =C2=A0with surrounding quotes and all */ > +static int > +encode_string(void* vctx, ERL_NIF_TERM binary) > +{ > + =C2=A0 =C2=A0encode_ctx* ctx =3D (encode_ctx*)vctx; > + =C2=A0 =C2=A0ErlNifBinary bin; > + > + =C2=A0 =C2=A0if(!enif_inspect_binary(ctx->env, binary, &bin)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return NOMEM; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0fill_buffer(ctx, "\"", 1); > + =C2=A0 =C2=A0if (ctx->error) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return ctx->error; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0yajl_string_encode2(fill_buffer, ctx, bin.data, bin.size); > + =C2=A0 =C2=A0fill_buffer(ctx, "\"", 1); > + > + =C2=A0 =C2=A0return ctx->error; > +} > + > +static ERL_NIF_TERM > +no_mem_error(ErlNifEnv* env) > +{ > + =C2=A0 =C2=A0return enif_make_tuple(env, 2, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(env, "error"), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_make_atom(env, "insuffici= ent_memory")); > +} > + > +ERL_NIF_TERM > +final_encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) > +{ > + =C2=A0 =C2=A0ERL_NIF_TERM head =3D argv[0]; > + =C2=A0 =C2=A0ERL_NIF_TERM term; > + =C2=A0 =C2=A0double number; > + =C2=A0 =C2=A0encode_ctx ctx; > + > + =C2=A0 =C2=A0ctx.env =3D env; > + =C2=A0 =C2=A0ctx.fill_offset =3D 0; > + =C2=A0 =C2=A0ctx.error =3D 0; > + > + =C2=A0 =C2=A0if (!enif_alloc_binary_compat(env, 100, &ctx.bin)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return no_mem_error(env); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0while(enif_get_list_cell(env, head, &term, &head)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0ErlNifBinary termbin; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0const ERL_NIF_TERM* array; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0int arity; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0int code; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0// We scan the list, looking for things to w= rite into the binary, or > + =C2=A0 =C2=A0 =C2=A0 =C2=A0// encode and then write into the binary. We= encode values that are > + =C2=A0 =C2=A0 =C2=A0 =C2=A0// tuples tagged with a type and a value: {T= ype, Value} where Type > + =C2=A0 =C2=A0 =C2=A0 =C2=A0// is a an Integer and Value is what is to b= e encoded > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (enif_get_tuple(env, term, &arity, &array= )) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// It's a tuple to encode and = copy > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (arity !=3D 2 || !enif_get_= int(env, array[0], &code)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// not arity 2 o= r the first element isn't an int > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ctx.error =3D BA= DARG; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (code =3D=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// {0, String} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (encode_strin= g(&ctx, array[1]) !=3D SUCCESS) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0go= to done; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// {1, Double} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if(!enif_get_dou= ble(env, array[1], &number)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ct= x.error =3D BADARG; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0go= to done; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// We can't enco= de these. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (isnan(number= ) || isinf(number)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ct= x.error =3D BADARG; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0go= to done; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if ((ctx.error = =3D ensure_buffer(&ctx, 32)) !=3D SUCCESS) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0go= to done; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// write the str= ing into the buffer > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0snprintf((char*)= ctx.bin.data+ctx.fill_offset, 32, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0"%.16g", number); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// increment the= length > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ctx.fill_offset = +=3D strlen((char*)ctx.bin.data+ctx.fill_offset); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} else if (enif_inspect_binary(env, term, &t= ermbin)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// this is a regular binary, c= opy the contents into the buffer > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fill_buffer(&ctx, (char*)termb= in.data, termbin.size); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (ctx.error) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0//not a binary, not a tuple, w= tf! > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ctx.error =3D BADARG; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto done; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > +done: > + =C2=A0 =C2=A0if (ctx.error =3D=3D NOMEM) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_release_binary_compat(env, &ctx.bin); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return no_mem_error(env); > + =C2=A0 =C2=A0} else if (ctx.error =3D=3D BADARG) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_release_binary_compat(env, &ctx.bin); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return enif_make_badarg(env); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0// Resize the binary to our exact final size > + =C2=A0 =C2=A0if(!enif_realloc_binary_compat(env, &(ctx.bin), ctx.fill_o= ffset)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0enif_release_binary_compat(env, &ctx.bin); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return no_mem_error(env); > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0// make the binary term which transfers ownership > + =C2=A0 =C2=A0return enif_make_binary(env, &ctx.bin); > +} > + > > Added: couchdb/trunk/src/ejson/erl_nif_compat.h > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/erl_nif_compat.= h?rev=3D1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/erl_nif_compat.h (added) > +++ couchdb/trunk/src/ejson/erl_nif_compat.h Tue Apr =C2=A05 09:42:41 201= 1 > @@ -0,0 +1,102 @@ > +#ifndef ERL_NIF_COMPAT_H_ > +#define ERL_NIF_COMPAT_H_ > + > +#ifdef __cplusplus > +extern "C" { > +#endif /* __cplusplus */ > + > +#include "erl_nif.h" > + > + > +#if ERL_NIF_MAJOR_VERSION =3D=3D 0 && ERL_NIF_MINOR_VERSION =3D=3D 1 > +#define OTP_R13B03 > +#elif ERL_NIF_MAJOR_VERSION =3D=3D 1 && ERL_NIF_MINOR_VERSION =3D=3D 0 > +#define OTP_R13B04 > +#elif ERL_NIF_MAJOR_VERSION =3D=3D 2 && ERL_NIF_MINOR_VERSION =3D=3D 0 > +#define OTP_R14A > +#define OTP_R14B > +#define OTP_R14B01 > +#elif ERL_NIF_MAJOR_VERSION =3D=3D 2 && ERL_NIF_MINOR_VERSION =3D=3D 1 > +#define OTP_R14B02 > +#endif > + > + > +#ifdef OTP_R13B03 > + > +#define enif_open_resource_type_compat enif_open_resource_type > +#define enif_alloc_resource_compat enif_alloc_resource > +#define enif_release_resource_compat enif_release_resource > +#define enif_alloc_binary_compat enif_alloc_binary > +#define enif_alloc_compat enif_alloc > +#define enif_release_binary_compat enif_release_binary > +#define enif_free_compat enif_free > +#define enif_get_atom_compat enif_get_atom > +#define enif_priv_data_compat enif_get_data > +#define enif_make_uint_compat enif_make_ulong > + > +#define enif_make_string_compat(E, B, Enc) \ > + =C2=A0 =C2=A0enif_make_string(E, B) > + > +#endif /* R13B03 */ > + > + > +#ifdef OTP_R13B04 > + > +#define enif_open_resource_type_compat enif_open_resource_type > +#define enif_alloc_resource_compat enif_alloc_resource > +#define enif_release_resource_compat enif_release_resource > +#define enif_alloc_binary_compat enif_alloc_binary > +#define enif_realloc_binary_compat enif_realloc_binary > +#define enif_release_binary_compat enif_release_binary > +#define enif_alloc_compat enif_alloc > +#define enif_free_compat enif_free > +#define enif_get_atom_compat enif_get_atom > +#define enif_priv_data_compat enif_priv_data > +#define enif_make_string_compat enif_make_string > +#define enif_make_uint_compat enif_make_uint > + > +#endif /* R13B04 */ > + > + > +/* OTP R14 and future releases */ > +#if !defined(OTP_R13B03) && !defined(OTP_R13B04) > + > +#define enif_open_resource_type_compat(E, N, D, F, T) \ > + =C2=A0 =C2=A0enif_open_resource_type(E, NULL, N, D, F, T) > + > +#define enif_alloc_resource_compat(E, T, S) \ > + =C2=A0 =C2=A0enif_alloc_resource(T, S) > + > +#define enif_release_resource_compat(E, H) \ > + =C2=A0 =C2=A0enif_release_resource(H) > + > +#define enif_alloc_binary_compat(E, S, B) \ > + =C2=A0 =C2=A0enif_alloc_binary(S, B) > + > +#define enif_realloc_binary_compat(E, S, B) \ > + =C2=A0 =C2=A0enif_realloc_binary(S, B) > + > +#define enif_release_binary_compat(E, B) \ > + =C2=A0 =C2=A0enif_release_binary(B) > + > +#define enif_alloc_compat(E, S) \ > + =C2=A0 =C2=A0enif_alloc(S) > + > +#define enif_free_compat(E, P) \ > + =C2=A0 =C2=A0enif_free(P) > + > +#define enif_get_atom_compat(E, T, B, S) \ > + =C2=A0 =C2=A0enif_get_atom(E, T, B, S, ERL_NIF_LATIN1) > + > +#define enif_priv_data_compat enif_priv_data > +#define enif_make_string_compat enif_make_string > +#define enif_make_uint_compat enif_make_uint > + > +#endif =C2=A0/* R14 and future releases */ > + > + > +#ifdef __cplusplus > +} > +#endif /* __cplusplus */ > + > +#endif /* ERL_NIF_COMPAT_H_ */ > > Added: couchdb/trunk/src/ejson/mochijson2.erl > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/mochijson2.erl?= rev=3D1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/mochijson2.erl (added) > +++ couchdb/trunk/src/ejson/mochijson2.erl Tue Apr =C2=A05 09:42:41 2011 > @@ -0,0 +1,849 @@ > +%% @author Bob Ippolito > +%% @copyright 2007 Mochi Media, Inc. > + > +%% @doc Yet another JSON (RFC 4627) library for Erlang. mochijson2 works > +%% =C2=A0 =C2=A0 =C2=A0with binaries as strings, arrays as lists (withou= t an {array, _}) > +%% =C2=A0 =C2=A0 =C2=A0wrapper and it only knows how to decode UTF-8 (an= d ASCII). > +%% > +%% =C2=A0 =C2=A0 =C2=A0JSON terms are decoded as follows (javascript -> = erlang): > +%% =C2=A0 =C2=A0 =C2=A0
    > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • {"key": "value"} -> > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{struct, [{<<"k= ey">>, <<"value">>}]}
  • > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • ["array", 123, 12.34, true, fal= se, null] -> > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[<<"array">>, 1= 23, 12.34, true, false, null] > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • > +%% =C2=A0 =C2=A0 =C2=A0
> +%% =C2=A0 =C2=A0 =C2=A0
    > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • Strings in JSON decode to UTF-8= binaries in Erlang
  • > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • Objects decode to {struct, Prop= List}
  • > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • Numbers decode to integer or fl= oat
  • > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • true, false, null decode to the= ir respective terms.
  • > +%% =C2=A0 =C2=A0 =C2=A0
> +%% =C2=A0 =C2=A0 =C2=A0The encoder will accept the same format that the = decoder will produce, > +%% =C2=A0 =C2=A0 =C2=A0but will also allow additional cases for leniency= : > +%% =C2=A0 =C2=A0 =C2=A0
    > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • atoms other than true, false, n= ull will be considered UTF-8 > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0strings (even as a pr= oplist key) > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • {json, IoList} will insert IoLi= st directly into the output > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0with no validation > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • {array, Array} will be encoded = as Array > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(legacy mochijson sty= le) > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • A non-empty raw proplist will b= e encoded as an object as long > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0as the first pair doe= s not have an atom key of json, struct, > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0or array > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
  • > +%% =C2=A0 =C2=A0 =C2=A0
> + > +-module(mochijson2). > +-author('bob@mochimedia.com'). > +-export([encoder/1, encode/1]). > +-export([decoder/1, decode/1]). > + > +% This is a macro to placate syntax highlighters.. > +-define(Q, $\"). > +-define(ADV_COL(S, N), S#decoder{offset=3DN+S#decoder.offset, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 column=3DN+S#decoder.column}). > +-define(INC_COL(S), S#decoder{offset=3D1+S#decoder.offset, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0column=3D1+S#decoder.column}). > +-define(INC_LINE(S), S#decoder{offset=3D1+S#decoder.offset, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 column=3D1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 line=3D1+S#decoder.line}). > +-define(INC_CHAR(S, C), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case C of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0$\n -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0S#decoder{column= =3D1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0line=3D1+S#decoder.line, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0offset=3D1+S#decoder.offset}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0S#decoder{column= =3D1+S#decoder.column, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0offset=3D1+S#decoder.offset} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0end). > +-define(IS_WHITESPACE(C), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0(C =3D:=3D $\s orelse C =3D:=3D $\t orelse C= =3D:=3D $\r orelse C =3D:=3D $\n)). > + > +%% @type iolist() =3D [char() | binary() | iolist()] > +%% @type iodata() =3D iolist() | binary() > +%% @type json_string() =3D atom | binary() > +%% @type json_number() =3D integer() | float() > +%% @type json_array() =3D [json_term()] > +%% @type json_object() =3D {struct, [{json_string(), json_term()}]} > +%% @type json_iolist() =3D {json, iolist()} > +%% @type json_term() =3D json_string() | json_number() | json_array() | > +%% =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= json_object() | json_iolist() > + > +-record(encoder, {handler=3Dnull, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0utf8=3Dfa= lse}). > + > +-record(decoder, {object_hook=3Dnull, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0offset=3D= 0, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0line=3D1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0column=3D= 1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0state=3Dn= ull}). > + > +%% @spec encoder([encoder_option()]) -> function() > +%% @doc Create an encoder/1 with the given options. > +%% @type encoder_option() =3D handler_option() | utf8_option() > +%% @type utf8_option() =3D boolean(). Emit unicode as utf8 (default - fa= lse) > +encoder(Options) -> > + =C2=A0 =C2=A0State =3D parse_encoder_options(Options, #encoder{}), > + =C2=A0 =C2=A0fun (O) -> json_encode(O, State) end. > + > +%% @spec encode(json_term()) -> iolist() > +%% @doc Encode the given as JSON to an iolist. > +encode(Any) -> > + =C2=A0 =C2=A0json_encode(Any, #encoder{}). > + > +%% @spec decoder([decoder_option()]) -> function() > +%% @doc Create a decoder/1 with the given options. > +decoder(Options) -> > + =C2=A0 =C2=A0State =3D parse_decoder_options(Options, #decoder{}), > + =C2=A0 =C2=A0fun (O) -> json_decode(O, State) end. > + > +%% @spec decode(iolist()) -> json_term() > +%% @doc Decode the given iolist to Erlang terms. > +decode(S) -> > + =C2=A0 =C2=A0json_decode(S, #decoder{}). > + > +%% Internal API > + > +parse_encoder_options([], State) -> > + =C2=A0 =C2=A0State; > +parse_encoder_options([{handler, Handler} | Rest], State) -> > + =C2=A0 =C2=A0parse_encoder_options(Rest, State#encoder{handler=3DHandle= r}); > +parse_encoder_options([{utf8, Switch} | Rest], State) -> > + =C2=A0 =C2=A0parse_encoder_options(Rest, State#encoder{utf8=3DSwitch}). > + > +parse_decoder_options([], State) -> > + =C2=A0 =C2=A0State; > +parse_decoder_options([{object_hook, Hook} | Rest], State) -> > + =C2=A0 =C2=A0parse_decoder_options(Rest, State#decoder{object_hook=3DHo= ok}). > + > +json_encode(true, _State) -> > + =C2=A0 =C2=A0<<"true">>; > +json_encode(false, _State) -> > + =C2=A0 =C2=A0<<"false">>; > +json_encode(null, _State) -> > + =C2=A0 =C2=A0<<"null">>; > +json_encode(I, _State) when is_integer(I) -> > + =C2=A0 =C2=A0integer_to_list(I); > +json_encode(F, _State) when is_float(F) -> > + =C2=A0 =C2=A0mochinum:digits(F); > +json_encode(S, State) when is_binary(S); is_atom(S) -> > + =C2=A0 =C2=A0json_encode_string(S, State); > +json_encode([{K, _}|_] =3D Props, State) when (K =3D/=3D struct andalso > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 K =3D/=3D array andalso > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 K =3D/=3D json) -> > + =C2=A0 =C2=A0json_encode_proplist(Props, State); > +json_encode({struct, Props}, State) when is_list(Props) -> > + =C2=A0 =C2=A0json_encode_proplist(Props, State); > +json_encode(Array, State) when is_list(Array) -> > + =C2=A0 =C2=A0json_encode_array(Array, State); > +json_encode({array, Array}, State) when is_list(Array) -> > + =C2=A0 =C2=A0json_encode_array(Array, State); > +json_encode({json, IoList}, _State) -> > + =C2=A0 =C2=A0IoList; > +json_encode(Bad, #encoder{handler=3Dnull}) -> > + =C2=A0 =C2=A0exit({json_encode, {bad_term, Bad}}); > +json_encode(Bad, State=3D#encoder{handler=3DHandler}) -> > + =C2=A0 =C2=A0json_encode(Handler(Bad), State). > + > +json_encode_array([], _State) -> > + =C2=A0 =C2=A0<<"[]">>; > +json_encode_array(L, State) -> > + =C2=A0 =C2=A0F =3D fun (O, Acc) -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[$,, json_encode= (O, State) | Acc] > + =C2=A0 =C2=A0 =C2=A0 =C2=A0end, > + =C2=A0 =C2=A0[$, | Acc1] =3D lists:foldl(F, "[", L), > + =C2=A0 =C2=A0lists:reverse([$\] | Acc1]). > + > +json_encode_proplist([], _State) -> > + =C2=A0 =C2=A0<<"{}">>; > +json_encode_proplist(Props, State) -> > + =C2=A0 =C2=A0F =3D fun ({K, V}, Acc) -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0KS =3D json_enco= de_string(K, State), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0VS =3D json_enco= de(V, State), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[$,, VS, $:, KS = | Acc] > + =C2=A0 =C2=A0 =C2=A0 =C2=A0end, > + =C2=A0 =C2=A0[$, | Acc1] =3D lists:foldl(F, "{", Props), > + =C2=A0 =C2=A0lists:reverse([$\} | Acc1]). > + > +json_encode_string(A, State) when is_atom(A) -> > + =C2=A0 =C2=A0L =3D atom_to_list(A), > + =C2=A0 =C2=A0case json_string_is_safe(L) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[?Q, L, ?Q]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0json_encode_string_unicode(xme= rl_ucs:from_utf8(L), State, [?Q]) > + =C2=A0 =C2=A0end; > +json_encode_string(B, State) when is_binary(B) -> > + =C2=A0 =C2=A0case json_bin_is_safe(B) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[?Q, B, ?Q]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0json_encode_string_unicode(xme= rl_ucs:from_utf8(B), State, [?Q]) > + =C2=A0 =C2=A0end; > +json_encode_string(I, _State) when is_integer(I) -> > + =C2=A0 =C2=A0[?Q, integer_to_list(I), ?Q]; > +json_encode_string(L, State) when is_list(L) -> > + =C2=A0 =C2=A0case json_string_is_safe(L) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[?Q, L, ?Q]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0json_encode_string_unicode(L, = State, [?Q]) > + =C2=A0 =C2=A0end. > + > +json_string_is_safe([]) -> > + =C2=A0 =C2=A0true; > +json_string_is_safe([C | Rest]) -> > + =C2=A0 =C2=A0case C of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0?Q -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\\ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\b -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\f -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\n -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\r -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\t -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0C when C >=3D 0, C < $\s; C >=3D 16#7f, C = =3D< 16#10FFFF -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0C when C < 16#7f -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0json_string_is_safe(Rest); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false > + =C2=A0 =C2=A0end. > + > +json_bin_is_safe(<<>>) -> > + =C2=A0 =C2=A0true; > +json_bin_is_safe(<>) -> > + =C2=A0 =C2=A0case C of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0?Q -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\\ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\b -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\f -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\n -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\r -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0$\t -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0C when C >=3D 0, C < $\s; C >=3D 16#7f -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0C when C < 16#7f -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0json_bin_is_safe(Rest) > + =C2=A0 =C2=A0end. > + > +json_encode_string_unicode([], _State, Acc) -> > + =C2=A0 =C2=A0lists:reverse([$\" | Acc]); > +json_encode_string_unicode([C | Cs], State, Acc) -> > + =C2=A0 =C2=A0Acc1 =3D case C of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ?Q -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [?Q, $\\= | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% Escaping solidus is= only useful when trying to protect > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% against ""= injection attacks which are only > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% possible when JSON = is inserted into a HTML document > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% in-line. mochijson2= does not protect you from this, so > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% if you do insert di= rectly into HTML then you need to > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% uncomment the follo= wing case or escape the output of encode. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% $/ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% =C2=A0 =C2=A0[$/, $= \\ | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 %% > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $\\ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [$\\, $\= \ | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $\b -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [$b, $\\= | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $\f -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [$f, $\\= | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $\n -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [$n, $\\= | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $\r -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [$r, $\\= | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $\t -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [$t, $\\= | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 C when C >=3D 0, C < $= \s -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [unihex(= C) | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 C when C >=3D 16#7f, C= =3D< 16#10FFFF, State#encoder.utf8 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [xmerl_u= cs:to_utf8(C) | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 C when =C2=A0C >=3D 16= #7f, C =3D< 16#10FFFF, not State#encoder.utf8 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [unihex(= C) | Acc]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 C when C < 16#7f -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [C | Acc= ]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 _ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 exit({js= on_encode, {bad_char, C}}) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 end, > + =C2=A0 =C2=A0json_encode_string_unicode(Cs, State, Acc1). > + > +hexdigit(C) when C >=3D 0, C =3D< 9 -> > + =C2=A0 =C2=A0C + $0; > +hexdigit(C) when C =3D< 15 -> > + =C2=A0 =C2=A0C + $a - 10. > + > +unihex(C) when C < 16#10000 -> > + =C2=A0 =C2=A0<> =3D <>, > + =C2=A0 =C2=A0Digits =3D [hexdigit(D) || D <- [D3, D2, D1, D0]], > + =C2=A0 =C2=A0[$\\, $u | Digits]; > +unihex(C) when C =3D< 16#10FFFF -> > + =C2=A0 =C2=A0N =3D C - 16#10000, > + =C2=A0 =C2=A0S1 =3D 16#d800 bor ((N bsr 10) band 16#3ff), > + =C2=A0 =C2=A0S2 =3D 16#dc00 bor (N band 16#3ff), > + =C2=A0 =C2=A0[unihex(S1), unihex(S2)]. > + > +json_decode(L, S) when is_list(L) -> > + =C2=A0 =C2=A0json_decode(iolist_to_binary(L), S); > +json_decode(B, S) -> > + =C2=A0 =C2=A0{Res, S1} =3D decode1(B, S), > + =C2=A0 =C2=A0{eof, _} =3D tokenize(B, S1#decoder{state=3Dtrim}), > + =C2=A0 =C2=A0Res. > + > +decode1(B, S=3D#decoder{state=3Dnull}) -> > + =C2=A0 =C2=A0case tokenize(B, S#decoder{state=3Dany}) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, C}, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{C, S1}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{start_array, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0decode_array(B, S1); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{start_object, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0decode_object(B, S1) > + =C2=A0 =C2=A0end. > + > +make_object(V, #decoder{object_hook=3Dnull}) -> > + =C2=A0 =C2=A0V; > +make_object(V, #decoder{object_hook=3DHook}) -> > + =C2=A0 =C2=A0Hook(V). > + > +decode_object(B, S) -> > + =C2=A0 =C2=A0decode_object(B, S#decoder{state=3Dkey}, []). > + > +decode_object(B, S=3D#decoder{state=3Dkey}, Acc) -> > + =C2=A0 =C2=A0case tokenize(B, S) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{end_object, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0V =3D make_object({struct, lis= ts:reverse(Acc)}, S1), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{V, S1#decoder{state=3Dnull}}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, K}, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{colon, S2} =3D tokenize(B, S1= ), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{V, S3} =3D decode1(B, S2#deco= der{state=3Dnull}), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0decode_object(B, S3#decoder{st= ate=3Dcomma}, [{K, V} | Acc]) > + =C2=A0 =C2=A0end; > +decode_object(B, S=3D#decoder{state=3Dcomma}, Acc) -> > + =C2=A0 =C2=A0case tokenize(B, S) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{end_object, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0V =3D make_object({struct, lis= ts:reverse(Acc)}, S1), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{V, S1#decoder{state=3Dnull}}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{comma, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0decode_object(B, S1#decoder{st= ate=3Dkey}, Acc) > + =C2=A0 =C2=A0end. > + > +decode_array(B, S) -> > + =C2=A0 =C2=A0decode_array(B, S#decoder{state=3Dany}, []). > + > +decode_array(B, S=3D#decoder{state=3Dany}, Acc) -> > + =C2=A0 =C2=A0case tokenize(B, S) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{end_array, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{lists:reverse(Acc), S1#decode= r{state=3Dnull}}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{start_array, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{Array, S2} =3D decode_array(B= , S1), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0decode_array(B, S2#decoder{sta= te=3Dcomma}, [Array | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{start_object, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{Array, S2} =3D decode_object(= B, S1), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0decode_array(B, S2#decoder{sta= te=3Dcomma}, [Array | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, Const}, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0decode_array(B, S1#decoder{sta= te=3Dcomma}, [Const | Acc]) > + =C2=A0 =C2=A0end; > +decode_array(B, S=3D#decoder{state=3Dcomma}, Acc) -> > + =C2=A0 =C2=A0case tokenize(B, S) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{end_array, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{lists:reverse(Acc), S1#decode= r{state=3Dnull}}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{comma, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0decode_array(B, S1#decoder{sta= te=3Dany}, Acc) > + =C2=A0 =C2=A0end. > + > +tokenize_string(B, S=3D#decoder{offset=3DO}) -> > + =C2=A0 =C2=A0case tokenize_string_fast(B, O) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{escape, O1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Length =3D O1 - O, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0S1 =3D ?ADV_COL(S, Length), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, Head:Length/bina= ry, _/binary>> =3D B, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, S1, lists:r= everse(binary_to_list(Head))); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0O1 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Length =3D O1 - O, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, String:Length/bi= nary, ?Q, _/binary>> =3D B, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, String}, ?ADV_COL(S, = Length + 1)} > + =C2=A0 =C2=A0end. > + > +tokenize_string_fast(B, O) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, ?Q, _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0O; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, $\\, _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{escape, O}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C1, _/binary>> when C1 < 128 -= > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string_fast(B, 1 + O)= ; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C1, C2, _/binary>> when C1 >= =3D 194, C1 =3D< 223, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C2 >=3D 128, C2 = =3D< 191 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string_fast(B, 2 + O)= ; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C1, C2, C3, _/binary>> when C1= >=3D 224, C1 =3D< 239, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C2 >=3D 128, C2 = =3D< 191, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C3 >=3D 128, C3 = =3D< 191 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string_fast(B, 3 + O)= ; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C1, C2, C3, C4, _/binary>> whe= n C1 >=3D 240, C1 =3D< 244, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C2 >=3D 128, C2 = =3D< 191, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C3 >=3D 128, C3 = =3D< 191, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C4 >=3D 128, C4 = =3D< 191 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string_fast(B, 4 + O)= ; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0throw(invalid_utf8) > + =C2=A0 =C2=A0end. > + > +tokenize_string(B, S=3D#decoder{offset=3DO}, Acc) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, ?Q, _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, iolist_to_binary(list= s:reverse(Acc))}, ?INC_COL(S)}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\\\"", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 2), [$\" | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\\\\", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 2), [$\\ | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\\/", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 2), [$/ | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\\b", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 2), [$\b | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\\f", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 2), [$\f | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\\n", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 2), [$\n | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\\r", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 2), [$\r | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\\t", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 2), [$\t | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\\u", C3, C2, C1, C0, Rest/bi= nary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C =3D erlang:list_to_integer([= C3, C2, C1, C0], 16), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if C > 16#D7FF, C < 16#DC00 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0%% coalesce UTF-= 16 surrogate pair > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<<"\\u", D3, D2,= D1, D0, _/binary>> =3D Rest, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0D =3D erlang:lis= t_to_integer([D3,D2,D1,D0], 16), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[CodePoint] =3D = xmerl_ucs:from_utf16be(< + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0D:= 16/big-unsigned-integer>>), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Acc1 =3D lists:r= everse(xmerl_ucs:to_utf8(CodePoint), Acc), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(= B, ?ADV_COL(S, 12), Acc1); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Acc1 =3D lists:r= everse(xmerl_ucs:to_utf8(C), Acc), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(= B, ?ADV_COL(S, 6), Acc1) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0end; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C1, _/binary>> when C1 < 128 -= > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?INC_CHAR(S= , C1), [C1 | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C1, C2, _/binary>> when C1 >= =3D 194, C1 =3D< 223, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C2 >=3D 128, C2 = =3D< 191 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 2), [C2, C1 | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C1, C2, C3, _/binary>> when C1= >=3D 224, C1 =3D< 239, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C2 >=3D 128, C2 = =3D< 191, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C3 >=3D 128, C3 = =3D< 191 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 3), [C3, C2, C1 | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C1, C2, C3, C4, _/binary>> whe= n C1 >=3D 240, C1 =3D< 244, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C2 >=3D 128, C2 = =3D< 191, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C3 >=3D 128, C3 = =3D< 191, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0C4 >=3D 128, C4 = =3D< 191 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?ADV_COL(S,= 4), [C4, C3, C2, C1 | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0throw(invalid_utf8) > + =C2=A0 =C2=A0end. > + > +tokenize_number(B, S) -> > + =C2=A0 =C2=A0case tokenize_number(B, sign, S, []) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{{int, Int}, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, list_to_integer(Int)}= , S1}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{{float, Float}, S1} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, list_to_float(Float)}= , S1} > + =C2=A0 =C2=A0end. > + > +tokenize_number(B, sign, S=3D#decoder{offset=3DO}, []) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, $-, _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, int, ?INC_C= OL(S), [$-]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, int, S, []) > + =C2=A0 =C2=A0end; > +tokenize_number(B, int, S=3D#decoder{offset=3DO}, Acc) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, $0, _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, frac, ?INC_= COL(S), [$0 | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C, _/binary>> when C >=3D $1 a= ndalso C =3D< $9 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, int1, ?INC_= COL(S), [C | Acc]) > + =C2=A0 =C2=A0end; > +tokenize_number(B, int1, S=3D#decoder{offset=3DO}, Acc) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C, _/binary>> when C >=3D $0 a= ndalso C =3D< $9 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, int1, ?INC_= COL(S), [C | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, frac, S, Ac= c) > + =C2=A0 =C2=A0end; > +tokenize_number(B, frac, S=3D#decoder{offset=3DO}, Acc) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, $., C, _/binary>> when C >=3D = $0, C =3D< $9 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, frac1, ?ADV= _COL(S, 2), [C, $. | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, E, _/binary>> when E =3D:=3D $= e orelse E =3D:=3D $E -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, esign, ?INC= _COL(S), [$e, $0, $. | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{int, lists:reverse(Acc)}, S} > + =C2=A0 =C2=A0end; > +tokenize_number(B, frac1, S=3D#decoder{offset=3DO}, Acc) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C, _/binary>> when C >=3D $0 a= ndalso C =3D< $9 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, frac1, ?INC= _COL(S), [C | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, E, _/binary>> when E =3D:=3D $= e orelse E =3D:=3D $E -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, esign, ?INC= _COL(S), [$e | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{float, lists:reverse(Acc)}, = S} > + =C2=A0 =C2=A0end; > +tokenize_number(B, esign, S=3D#decoder{offset=3DO}, Acc) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C, _/binary>> when C =3D:=3D $= - orelse C=3D:=3D $+ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, eint, ?INC_= COL(S), [C | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, eint, S, Ac= c) > + =C2=A0 =C2=A0end; > +tokenize_number(B, eint, S=3D#decoder{offset=3DO}, Acc) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C, _/binary>> when C >=3D $0 a= ndalso C =3D< $9 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, eint1, ?INC= _COL(S), [C | Acc]) > + =C2=A0 =C2=A0end; > +tokenize_number(B, eint1, S=3D#decoder{offset=3DO}, Acc) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C, _/binary>> when C >=3D $0 a= ndalso C =3D< $9 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, eint1, ?INC= _COL(S), [C | Acc]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{float, lists:reverse(Acc)}, = S} > + =C2=A0 =C2=A0end. > + > +tokenize(B, S=3D#decoder{offset=3DO}) -> > + =C2=A0 =C2=A0case B of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C, _/binary>> when ?IS_WHITESP= ACE(C) -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize(B, ?INC_CHAR(S, C)); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "{", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{start_object, ?INC_COL(S)}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "}", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{end_object, ?INC_COL(S)}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "[", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{start_array, ?INC_COL(S)}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "]", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{end_array, ?INC_COL(S)}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, ",", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{comma, ?INC_COL(S)}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, ":", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{colon, ?INC_COL(S)}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "null", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, null}, ?ADV_COL(S, 4)= }; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "true", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, true}, ?ADV_COL(S, 4)= }; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "false", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{{const, false}, ?ADV_COL(S, 5= )}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, "\"", _/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_string(B, ?INC_COL(S)= ); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary, C, _/binary>> when (C >=3D $0 = andalso C =3D< $9) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 orels= e C =3D:=3D $- -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tokenize_number(B, S); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<<_:O/binary>> -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0trim =3D S#decoder.state, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{eof, S} > + =C2=A0 =C2=A0end. > +%% > +%% Tests > +%% > +-ifdef(TEST). > +-include_lib("eunit/include/eunit.hrl"). > + > + > +%% testing constructs borrowed from the Yaws JSON implementation. > + > +%% Create an object from a list of Key/Value pairs. > + > +obj_new() -> > + =C2=A0 =C2=A0{struct, []}. > + > +is_obj({struct, Props}) -> > + =C2=A0 =C2=A0F =3D fun ({K, _}) when is_binary(K) -> true end, > + =C2=A0 =C2=A0lists:all(F, Props). > + > +obj_from_list(Props) -> > + =C2=A0 =C2=A0Obj =3D {struct, Props}, > + =C2=A0 =C2=A0?assert(is_obj(Obj)), > + =C2=A0 =C2=A0Obj. > + > +%% Test for equivalence of Erlang terms. > +%% Due to arbitrary order of construction, equivalent objects might > +%% compare unequal as erlang terms, so we need to carefully recurse > +%% through aggregates (tuples and objects). > + > +equiv({struct, Props1}, {struct, Props2}) -> > + =C2=A0 =C2=A0equiv_object(Props1, Props2); > +equiv(L1, L2) when is_list(L1), is_list(L2) -> > + =C2=A0 =C2=A0equiv_list(L1, L2); > +equiv(N1, N2) when is_number(N1), is_number(N2) -> N1 =3D=3D N2; > +equiv(B1, B2) when is_binary(B1), is_binary(B2) -> B1 =3D=3D B2; > +equiv(A, A) when A =3D:=3D true orelse A =3D:=3D false orelse A =3D:=3D = null -> true. > + > +%% Object representation and traversal order is unknown. > +%% Use the sledgehammer and sort property lists. > + > +equiv_object(Props1, Props2) -> > + =C2=A0 =C2=A0L1 =3D lists:keysort(1, Props1), > + =C2=A0 =C2=A0L2 =3D lists:keysort(1, Props2), > + =C2=A0 =C2=A0Pairs =3D lists:zip(L1, L2), > + =C2=A0 =C2=A0true =3D lists:all(fun({{K1, V1}, {K2, V2}}) -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 equiv(K1, K2) and equiv(V1, V2) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 e= nd, Pairs). > + > +%% Recursively compare tuple elements for equivalence. > + > +equiv_list([], []) -> > + =C2=A0 =C2=A0true; > +equiv_list([V1 | L1], [V2 | L2]) -> > + =C2=A0 =C2=A0equiv(V1, V2) andalso equiv_list(L1, L2). > + > +decode_test() -> > + =C2=A0 =C2=A0[1199344435545.0, 1] =3D decode(<<"[1199344435545.0,1]">>)= , > + =C2=A0 =C2=A0<<16#F0,16#9D,16#9C,16#95>> =3D decode([34,"\\ud835","\\ud= f15",34]). > + > +e2j_vec_test() -> > + =C2=A0 =C2=A0test_one(e2j_test_vec(utf8), 1). > + > +test_one([], _N) -> > + =C2=A0 =C2=A0%% io:format("~p tests passed~n", [N-1]), > + =C2=A0 =C2=A0ok; > +test_one([{E, J} | Rest], N) -> > + =C2=A0 =C2=A0%% io:format("[~p] ~p ~p~n", [N, E, J]), > + =C2=A0 =C2=A0true =3D equiv(E, decode(J)), > + =C2=A0 =C2=A0true =3D equiv(E, decode(encode(E))), > + =C2=A0 =C2=A0test_one(Rest, 1+N). > + > +e2j_test_vec(utf8) -> > + =C2=A0 =C2=A0[ > + =C2=A0 =C2=A0 {1, "1"}, > + =C2=A0 =C2=A0 {3.1416, "3.14160"}, %% text representation may truncate,= trail zeroes > + =C2=A0 =C2=A0 {-1, "-1"}, > + =C2=A0 =C2=A0 {-3.1416, "-3.14160"}, > + =C2=A0 =C2=A0 {12.0e10, "1.20000e+11"}, > + =C2=A0 =C2=A0 {1.234E+10, "1.23400e+10"}, > + =C2=A0 =C2=A0 {-1.234E-10, "-1.23400e-10"}, > + =C2=A0 =C2=A0 {10.0, "1.0e+01"}, > + =C2=A0 =C2=A0 {123.456, "1.23456E+2"}, > + =C2=A0 =C2=A0 {10.0, "1e1"}, > + =C2=A0 =C2=A0 {<<"foo">>, "\"foo\""}, > + =C2=A0 =C2=A0 {<<"foo", 5, "bar">>, "\"foo\\u0005bar\""}, > + =C2=A0 =C2=A0 {<<"">>, "\"\""}, > + =C2=A0 =C2=A0 {<<"\n\n\n">>, "\"\\n\\n\\n\""}, > + =C2=A0 =C2=A0 {<<"\" \b\f\r\n\t\"">>, "\"\\\" \\b\\f\\r\\n\\t\\\"\""}, > + =C2=A0 =C2=A0 {obj_new(), "{}"}, > + =C2=A0 =C2=A0 {obj_from_list([{<<"foo">>, <<"bar">>}]), "{\"foo\":\"bar= \"}"}, > + =C2=A0 =C2=A0 {obj_from_list([{<<"foo">>, <<"bar">>}, {<<"baz">>, 123}]= ), > + =C2=A0 =C2=A0 =C2=A0"{\"foo\":\"bar\",\"baz\":123}"}, > + =C2=A0 =C2=A0 {[], "[]"}, > + =C2=A0 =C2=A0 {[[]], "[[]]"}, > + =C2=A0 =C2=A0 {[1, <<"foo">>], "[1,\"foo\"]"}, > + > + =C2=A0 =C2=A0 %% json array in a json object > + =C2=A0 =C2=A0 {obj_from_list([{<<"foo">>, [123]}]), > + =C2=A0 =C2=A0 =C2=A0"{\"foo\":[123]}"}, > + > + =C2=A0 =C2=A0 %% json object in a json object > + =C2=A0 =C2=A0 {obj_from_list([{<<"foo">>, obj_from_list([{<<"bar">>, tr= ue}])}]), > + =C2=A0 =C2=A0 =C2=A0"{\"foo\":{\"bar\":true}}"}, > + > + =C2=A0 =C2=A0 %% fold evaluation order > + =C2=A0 =C2=A0 {obj_from_list([{<<"foo">>, []}, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {= <<"bar">>, obj_from_list([{<<"baz">>, true}])}, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {= <<"alice">>, <<"bob">>}]), > + =C2=A0 =C2=A0 =C2=A0"{\"foo\":[],\"bar\":{\"baz\":true},\"alice\":\"bob= \"}"}, > + > + =C2=A0 =C2=A0 %% json object in a json array > + =C2=A0 =C2=A0 {[-123, <<"foo">>, obj_from_list([{<<"bar">>, []}]), null= ], > + =C2=A0 =C2=A0 =C2=A0"[-123,\"foo\",{\"bar\":[]},null]"} > + =C2=A0 =C2=A0]. > + > +%% test utf8 encoding > +encoder_utf8_test() -> > + =C2=A0 =C2=A0%% safe conversion case (default) > + =C2=A0 =C2=A0[34,"\\u0001","\\u0442","\\u0435","\\u0441","\\u0442",34] = =3D > + =C2=A0 =C2=A0 =C2=A0 =C2=A0encode(<<1,"\321\202\320\265\321\201\321\202= ">>), > + > + =C2=A0 =C2=A0%% raw utf8 output (optional) > + =C2=A0 =C2=A0Enc =3D mochijson2:encoder([{utf8, true}]), > + =C2=A0 =C2=A0[34,"\\u0001",[209,130],[208,181],[209,129],[209,130],34] = =3D > + =C2=A0 =C2=A0 =C2=A0 =C2=A0Enc(<<1,"\321\202\320\265\321\201\321\202">>= ). > + > +input_validation_test() -> > + =C2=A0 =C2=A0Good =3D [ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{16#00A3, <>}, %% poun= d > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{16#20AC, <>}, = %% euro > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{16#10196, <>} %% denarius > + =C2=A0 =C2=A0], > + =C2=A0 =C2=A0lists:foreach(fun({CodePoint, UTF8}) -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0Expect =3D list_to_binary(xmerl_ucs:to_utf8(= CodePoint)), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0Expect =3D decode(UTF8) > + =C2=A0 =C2=A0end, Good), > + > + =C2=A0 =C2=A0Bad =3D [ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0%% 2nd, 3rd, or 4th byte of a multi-byte seq= uence w/o leading byte > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<>, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0%% missing continuations, last byte in each = should be 80-BF > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<>, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<>, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<>, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0%% we don't support code points > 10FFFF per= RFC 3629 > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<>, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0%% escape characters trigger a different cod= e path > + =C2=A0 =C2=A0 =C2=A0 =C2=A0<> > + =C2=A0 =C2=A0], > + =C2=A0 =C2=A0lists:foreach( > + =C2=A0 =C2=A0 =C2=A0fun(X) -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ok =3D try decode(X) ca= tch invalid_utf8 -> ok end, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0%% could be {ucs,{bad_u= tf8_character_code}} or > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0%% =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0{json_encode,{bad_char,_}} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{'EXIT', _} =3D (catch = encode(X)) > + =C2=A0 =C2=A0 =C2=A0end, Bad). > + > +inline_json_test() -> > + =C2=A0 =C2=A0?assertEqual(<<"\"iodata iodata\"">>, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 iolist_to_binar= y( > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 encode({= json, [<<"\"iodata">>, " iodata\""]}))), > + =C2=A0 =C2=A0?assertEqual({struct, [{<<"key">>, <<"iodata iodata">>}]}, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 decode( > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 encode({= struct, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 [{key, {json, [<<"\"iodata">>, " iodata\""]}}]}))), > + =C2=A0 =C2=A0ok. > + > +big_unicode_test() -> > + =C2=A0 =C2=A0UTF8Seq =3D list_to_binary(xmerl_ucs:to_utf8(16#0001d120))= , > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"\"\\ud834\\udd20\"">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode(UTF8Seq))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 UTF8Seq, > + =C2=A0 =C2=A0 =C2=A0 decode(iolist_to_binary(encode(UTF8Seq)))), > + =C2=A0 =C2=A0ok. > + > +custom_decoder_test() -> > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 {struct, [{<<"key">>, <<"value">>}]}, > + =C2=A0 =C2=A0 =C2=A0 (decoder([]))("{\"key\": \"value\"}")), > + =C2=A0 =C2=A0F =3D fun ({struct, [{<<"key">>, <<"value">>}]}) -> win en= d, > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 win, > + =C2=A0 =C2=A0 =C2=A0 (decoder([{object_hook, F}]))("{\"key\": \"value\"= }")), > + =C2=A0 =C2=A0ok. > + > +atom_test() -> > + =C2=A0 =C2=A0%% JSON native atoms > + =C2=A0 =C2=A0[begin > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 ?assertEqual(A, decode(atom_to_list(A))), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 ?assertEqual(iolist_to_binary(atom_to_list(= A)), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0iolist_to_binary(encode(A))) > + =C2=A0 =C2=A0 end || A <- [true, false, null]], > + =C2=A0 =C2=A0%% Atom to string > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"\"foo\"">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode(foo))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"\"\\ud834\\udd20\"">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode(list_to_atom(xmerl_ucs:to_= utf8(16#0001d120))))), > + =C2=A0 =C2=A0ok. > + > +key_encode_test() -> > + =C2=A0 =C2=A0%% Some forms are accepted as keys that would not be strin= gs in other > + =C2=A0 =C2=A0%% cases > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"{\"foo\":1}">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode({struct, [{foo, 1}]}))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"{\"foo\":1}">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode({struct, [{<<"foo">>, 1}]}= ))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"{\"foo\":1}">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode({struct, [{"foo", 1}]}))), > + =C2=A0 =C2=A0 =C2=A0 ?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"{\"foo\":1}">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode([{foo, 1}]))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"{\"foo\":1}">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode([{<<"foo">>, 1}]))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"{\"foo\":1}">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode([{"foo", 1}]))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"{\"\\ud834\\udd20\":1}">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary( > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 encode({struct, [{[16#0001d120], 1}]}))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"{\"1\":1}">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary(encode({struct, [{1, 1}]}))), > + =C2=A0 =C2=A0ok. > + > +unsafe_chars_test() -> > + =C2=A0 =C2=A0Chars =3D "\"\\\b\f\n\r\t", > + =C2=A0 =C2=A0[begin > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 ?assertEqual(false, json_string_is_safe([C]= )), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 ?assertEqual(false, json_bin_is_safe(<>)= ), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 ?assertEqual(<>, decode(encode(<>))) > + =C2=A0 =C2=A0 end || C <- Chars], > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 false, > + =C2=A0 =C2=A0 =C2=A0 json_string_is_safe([16#0001d120])), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 false, > + =C2=A0 =C2=A0 =C2=A0 json_bin_is_safe(list_to_binary(xmerl_ucs:to_utf8(= 16#0001d120)))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 [16#0001d120], > + =C2=A0 =C2=A0 =C2=A0 xmerl_ucs:from_utf8( > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 binary_to_list( > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 decode(encode(list_to_atom(xmerl_ucs= :to_utf8(16#0001d120))))))), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 false, > + =C2=A0 =C2=A0 =C2=A0 json_string_is_safe([16#110000])), > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 false, > + =C2=A0 =C2=A0 =C2=A0 json_bin_is_safe(list_to_binary(xmerl_ucs:to_utf8(= [16#110000])))), > + =C2=A0 =C2=A0%% solidus can be escaped but isn't unsafe by default > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"/">>, > + =C2=A0 =C2=A0 =C2=A0 decode(<<"\"\\/\"">>)), > + =C2=A0 =C2=A0ok. > + > +int_test() -> > + =C2=A0 =C2=A0?assertEqual(0, decode("0")), > + =C2=A0 =C2=A0?assertEqual(1, decode("1")), > + =C2=A0 =C2=A0?assertEqual(11, decode("11")), > + =C2=A0 =C2=A0ok. > + > +large_int_test() -> > + =C2=A0 =C2=A0?assertEqual(<<"-2147483649214748364921474836492147483649"= >>, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0iolist_to_binary(encode(-2147483649214748364= 921474836492147483649))), > + =C2=A0 =C2=A0?assertEqual(<<"2147483649214748364921474836492147483649">= >, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0iolist_to_binary(encode(21474836492147483649= 21474836492147483649))), > + =C2=A0 =C2=A0ok. > + > +float_test() -> > + =C2=A0 =C2=A0?assertEqual(<<"-2147483649.0">>, iolist_to_binary(encode(= -2147483649.0))), > + =C2=A0 =C2=A0?assertEqual(<<"2147483648.0">>, iolist_to_binary(encode(2= 147483648.0))), > + =C2=A0 =C2=A0ok. > + > +handler_test() -> > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 {'EXIT',{json_encode,{bad_term,{}}}}, > + =C2=A0 =C2=A0 =C2=A0 catch encode({})), > + =C2=A0 =C2=A0F =3D fun ({}) -> [] end, > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 <<"[]">>, > + =C2=A0 =C2=A0 =C2=A0 iolist_to_binary((encoder([{handler, F}]))({}))), > + =C2=A0 =C2=A0ok. > + > +-endif. > > Added: couchdb/trunk/src/ejson/mochinum.erl > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/mochinum.erl?re= v=3D1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/mochinum.erl (added) > +++ couchdb/trunk/src/ejson/mochinum.erl Tue Apr =C2=A05 09:42:41 2011 > @@ -0,0 +1,354 @@ > +%% @copyright 2007 Mochi Media, Inc. > +%% @author Bob Ippolito > + > +%% @doc Useful numeric algorithms for floats that cover some deficiencie= s > +%% in the math module. More interesting is digits/1, which implements > +%% the algorithm from: > +%% http://www.cs.indiana.edu/~burger/fp/index.html > +%% See also "Printing Floating-Point Numbers Quickly and Accurately" > +%% in Proceedings of the SIGPLAN '96 Conference on Programming Language > +%% Design and Implementation. > + > +-module(mochinum). > +-author("Bob Ippolito "). > +-export([digits/1, frexp/1, int_pow/2, int_ceil/1]). > + > +%% IEEE 754 Float exponent bias > +-define(FLOAT_BIAS, 1022). > +-define(MIN_EXP, -1074). > +-define(BIG_POW, 4503599627370496). > + > +%% External API > + > +%% @spec digits(number()) -> string() > +%% @doc =C2=A0Returns a string that accurately represents the given inte= ger or float > +%% =C2=A0 =C2=A0 =C2=A0 using a conservative amount of digits. Great for= generating > +%% =C2=A0 =C2=A0 =C2=A0 human-readable output, or compact ASCII serializ= ations for floats. > +digits(N) when is_integer(N) -> > + =C2=A0 =C2=A0integer_to_list(N); > +digits(0.0) -> > + =C2=A0 =C2=A0"0.0"; > +digits(Float) -> > + =C2=A0 =C2=A0{Frac1, Exp1} =3D frexp_int(Float), > + =C2=A0 =C2=A0[Place0 | Digits0] =3D digits1(Float, Exp1, Frac1), > + =C2=A0 =C2=A0{Place, Digits} =3D transform_digits(Place0, Digits0), > + =C2=A0 =C2=A0R =3D insert_decimal(Place, Digits), > + =C2=A0 =C2=A0case Float < 0 of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[$- | R]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0R > + =C2=A0 =C2=A0end. > + > +%% @spec frexp(F::float()) -> {Frac::float(), Exp::float()} > +%% @doc =C2=A0Return the fractional and exponent part of an IEEE 754 dou= ble, > +%% =C2=A0 =C2=A0 =C2=A0 equivalent to the libc function of the same name= . > +%% =C2=A0 =C2=A0 =C2=A0 F =3D Frac * pow(2, Exp). > +frexp(F) -> > + =C2=A0 =C2=A0frexp1(unpack(F)). > + > +%% @spec int_pow(X::integer(), N::integer()) -> Y::integer() > +%% @doc =C2=A0Moderately efficient way to exponentiate integers. > +%% =C2=A0 =C2=A0 =C2=A0 int_pow(10, 2) =3D 100. > +int_pow(_X, 0) -> > + =C2=A0 =C2=A01; > +int_pow(X, N) when N > 0 -> > + =C2=A0 =C2=A0int_pow(X, N, 1). > + > +%% @spec int_ceil(F::float()) -> integer() > +%% @doc =C2=A0Return the ceiling of F as an integer. The ceiling is defi= ned as > +%% =C2=A0 =C2=A0 =C2=A0 F when F =3D=3D trunc(F); > +%% =C2=A0 =C2=A0 =C2=A0 trunc(F) when F < 0; > +%% =C2=A0 =C2=A0 =C2=A0 trunc(F) + 1 when F > 0. > +int_ceil(X) -> > + =C2=A0 =C2=A0T =3D trunc(X), > + =C2=A0 =C2=A0case (X - T) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0Pos when Pos > 0 -> T + 1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> T > + =C2=A0 =C2=A0end. > + > + > +%% Internal API > + > +int_pow(X, N, R) when N < 2 -> > + =C2=A0 =C2=A0R * X; > +int_pow(X, N, R) -> > + =C2=A0 =C2=A0int_pow(X * X, N bsr 1, case N band 1 of 1 -> R * X; 0 -> = R end). > + > +insert_decimal(0, S) -> > + =C2=A0 =C2=A0"0." ++ S; > +insert_decimal(Place, S) when Place > 0 -> > + =C2=A0 =C2=A0L =3D length(S), > + =C2=A0 =C2=A0case Place - L of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 0 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0S ++ ".0"; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0N when N < 0 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{S0, S1} =3D lists:split(L + N= , S), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0S0 ++ "." ++ S1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0N when N < 6 -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0%% More places than digits > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0S ++ lists:duplicate(N, $0) ++= ".0"; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0_ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0insert_decimal_exp(Place, S) > + =C2=A0 =C2=A0end; > +insert_decimal(Place, S) when Place > -6 -> > + =C2=A0 =C2=A0"0." ++ lists:duplicate(abs(Place), $0) ++ S; > +insert_decimal(Place, S) -> > + =C2=A0 =C2=A0insert_decimal_exp(Place, S). > + > +insert_decimal_exp(Place, S) -> > + =C2=A0 =C2=A0[C | S0] =3D S, > + =C2=A0 =C2=A0S1 =3D case S0 of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [] -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "0"; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 _ -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 S0 > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 end, > + =C2=A0 =C2=A0Exp =3D case Place < 0 of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"e-"; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"e+" > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0end, > + =C2=A0 =C2=A0[C] ++ "." ++ S1 ++ Exp ++ integer_to_list(abs(Place - 1))= . > + > + > +digits1(Float, Exp, Frac) -> > + =C2=A0 =C2=A0Round =3D ((Frac band 1) =3D:=3D 0), > + =C2=A0 =C2=A0case Exp >=3D 0 of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BExp =3D 1 bsl Exp, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case (Frac =3D/=3D ?BIG_POW) o= f > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc= ale((Frac * BExp * 2), 2, BExp, BExp, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0Round, Round, Float); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc= ale((Frac * BExp * 4), 4, (BExp * 2), BExp, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0Round, Round, Float) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0end; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case (Exp =3D:=3D ?MIN_EXP) or= else (Frac =3D/=3D ?BIG_POW) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc= ale((Frac * 2), 1 bsl (1 - Exp), 1, 1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0Round, Round, Float); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc= ale((Frac * 4), 1 bsl (2 - Exp), 2, 1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0Round, Round, Float) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0end > + =C2=A0 =C2=A0end. > + > +scale(R, S, MPlus, MMinus, LowOk, HighOk, Float) -> > + =C2=A0 =C2=A0Est =3D int_ceil(math:log10(abs(Float)) - 1.0e-10), > + =C2=A0 =C2=A0%% Note that the scheme implementation uses a 326 element = look-up table > + =C2=A0 =C2=A0%% for int_pow(10, N) where we do not. > + =C2=A0 =C2=A0case Est >=3D 0 of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fixup(R, S * int_pow(10, Est),= MPlus, MMinus, Est, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0LowOk, Hi= ghOk); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Scale =3D int_pow(10, -Est), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fixup(R * Scale, S, MPlus * Sc= ale, MMinus * Scale, Est, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0LowOk, Hi= ghOk) > + =C2=A0 =C2=A0end. > + > +fixup(R, S, MPlus, MMinus, K, LowOk, HighOk) -> > + =C2=A0 =C2=A0TooLow =3D case HighOk of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= R + MPlus) >=3D S; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= R + MPlus) > S > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 end, > + =C2=A0 =C2=A0case TooLow of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[(K + 1) | generate(R, S, MPlu= s, MMinus, LowOk, HighOk)]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[K | generate(R * 10, S, MPlus= * 10, MMinus * 10, LowOk, HighOk)] > + =C2=A0 =C2=A0end. > + > +generate(R0, S, MPlus, MMinus, LowOk, HighOk) -> > + =C2=A0 =C2=A0D =3D R0 div S, > + =C2=A0 =C2=A0R =3D R0 rem S, > + =C2=A0 =C2=A0TC1 =3D case LowOk of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0R =3D< MM= inus; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0R < MMinu= s > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0end, > + =C2=A0 =C2=A0TC2 =3D case HighOk of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(R + MPlu= s) >=3D S; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(R + MPlu= s) > S > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0end, > + =C2=A0 =C2=A0case TC1 of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case TC2 of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[D= | generate(R * 10, S, MPlus * 10, MMinus * 10, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0LowOk, HighOk)]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[D= + 1] > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0end; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case TC2 of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[D= ]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ca= se R * 2 < S of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0true -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0[D]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0false -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0[D + 1] > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0en= d > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0end > + =C2=A0 =C2=A0end. > + > +unpack(Float) -> > + =C2=A0 =C2=A0<> =3D <>, > + =C2=A0 =C2=A0{Sign, Exp, Frac}. > + > +frexp1({_Sign, 0, 0}) -> > + =C2=A0 =C2=A0{0.0, 0}; > +frexp1({Sign, 0, Frac}) -> > + =C2=A0 =C2=A0Exp =3D log2floor(Frac), > + =C2=A0 =C2=A0<> =3D <>, > + =C2=A0 =C2=A0{Frac1, -(?FLOAT_BIAS) - 52 + Exp}; > +frexp1({Sign, Exp, Frac}) -> > + =C2=A0 =C2=A0<> =3D <>= , > + =C2=A0 =C2=A0{Frac1, Exp - ?FLOAT_BIAS}. > + > +log2floor(Int) -> > + =C2=A0 =C2=A0log2floor(Int, 0). > + > +log2floor(0, N) -> > + =C2=A0 =C2=A0N; > +log2floor(Int, N) -> > + =C2=A0 =C2=A0log2floor(Int bsr 1, 1 + N). > + > + > +transform_digits(Place, [0 | Rest]) -> > + =C2=A0 =C2=A0transform_digits(Place, Rest); > +transform_digits(Place, Digits) -> > + =C2=A0 =C2=A0{Place, [$0 + D || D <- Digits]}. > + > + > +frexp_int(F) -> > + =C2=A0 =C2=A0case unpack(F) of > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{_Sign, 0, Frac} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{Frac, ?MIN_EXP}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{_Sign, Exp, Frac} -> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{Frac + (1 bsl 52), Exp - 53 -= ?FLOAT_BIAS} > + =C2=A0 =C2=A0end. > + > +%% > +%% Tests > +%% > +-ifdef(TEST). > +-include_lib("eunit/include/eunit.hrl"). > + > +int_ceil_test() -> > + =C2=A0 =C2=A0?assertEqual(1, int_ceil(0.0001)), > + =C2=A0 =C2=A0?assertEqual(0, int_ceil(0.0)), > + =C2=A0 =C2=A0?assertEqual(1, int_ceil(0.99)), > + =C2=A0 =C2=A0?assertEqual(1, int_ceil(1.0)), > + =C2=A0 =C2=A0?assertEqual(-1, int_ceil(-1.5)), > + =C2=A0 =C2=A0?assertEqual(-2, int_ceil(-2.0)), > + =C2=A0 =C2=A0ok. > + > +int_pow_test() -> > + =C2=A0 =C2=A0?assertEqual(1, int_pow(1, 1)), > + =C2=A0 =C2=A0?assertEqual(1, int_pow(1, 0)), > + =C2=A0 =C2=A0?assertEqual(1, int_pow(10, 0)), > + =C2=A0 =C2=A0?assertEqual(10, int_pow(10, 1)), > + =C2=A0 =C2=A0?assertEqual(100, int_pow(10, 2)), > + =C2=A0 =C2=A0?assertEqual(1000, int_pow(10, 3)), > + =C2=A0 =C2=A0ok. > + > +digits_test() -> > + =C2=A0 =C2=A0?assertEqual("0", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(0)), > + =C2=A0 =C2=A0?assertEqual("0.0", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(0.0)), > + =C2=A0 =C2=A0?assertEqual("1.0", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(1.0)), > + =C2=A0 =C2=A0?assertEqual("-1.0", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(-1.0)), > + =C2=A0 =C2=A0?assertEqual("0.1", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(0.1)), > + =C2=A0 =C2=A0?assertEqual("0.01", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(0.01)), > + =C2=A0 =C2=A0?assertEqual("0.001", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(0.001)), > + =C2=A0 =C2=A0?assertEqual("1.0e+6", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(1000000.= 0)), > + =C2=A0 =C2=A0?assertEqual("0.5", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(0.5)), > + =C2=A0 =C2=A0?assertEqual("4503599627370496.0", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(45035996= 27370496.0)), > + =C2=A0 =C2=A0%% small denormalized number > + =C2=A0 =C2=A0%% 4.94065645841246544177e-324 =3D:=3D 5.0e-324 > + =C2=A0 =C2=A0<> =3D <<0,0,0,0,0,0,0,1>>, > + =C2=A0 =C2=A0?assertEqual("5.0e-324", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(SmallDen= orm)), > + =C2=A0 =C2=A0?assertEqual(SmallDenorm, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_to_float(d= igits(SmallDenorm))), > + =C2=A0 =C2=A0%% large denormalized number > + =C2=A0 =C2=A0%% 2.22507385850720088902e-308 > + =C2=A0 =C2=A0<> =3D <<0,15,255,255,255,255,255,255>>, > + =C2=A0 =C2=A0?assertEqual("2.225073858507201e-308", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(BigDenor= m)), > + =C2=A0 =C2=A0?assertEqual(BigDenorm, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_to_float(d= igits(BigDenorm))), > + =C2=A0 =C2=A0%% small normalized number > + =C2=A0 =C2=A0%% 2.22507385850720138309e-308 > + =C2=A0 =C2=A0<> =3D <<0,16,0,0,0,0,0,0>>, > + =C2=A0 =C2=A0?assertEqual("2.2250738585072014e-308", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(SmallNor= m)), > + =C2=A0 =C2=A0?assertEqual(SmallNorm, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_to_float(d= igits(SmallNorm))), > + =C2=A0 =C2=A0%% large normalized number > + =C2=A0 =C2=A0%% 1.79769313486231570815e+308 > + =C2=A0 =C2=A0<> =3D <<127,239,255,255,255,255,255,255>= >, > + =C2=A0 =C2=A0?assertEqual("1.7976931348623157e+308", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(LargeNor= m)), > + =C2=A0 =C2=A0?assertEqual(LargeNorm, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_to_float(d= igits(LargeNorm))), > + =C2=A0 =C2=A0%% issue #10 - mochinum:frexp(math:pow(2, -1074)). > + =C2=A0 =C2=A0?assertEqual("5.0e-324", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 digits(math:pow= (2, -1074))), > + =C2=A0 =C2=A0ok. > + > +frexp_test() -> > + =C2=A0 =C2=A0%% zero > + =C2=A0 =C2=A0?assertEqual({0.0, 0}, frexp(0.0)), > + =C2=A0 =C2=A0%% one > + =C2=A0 =C2=A0?assertEqual({0.5, 1}, frexp(1.0)), > + =C2=A0 =C2=A0%% negative one > + =C2=A0 =C2=A0?assertEqual({-0.5, 1}, frexp(-1.0)), > + =C2=A0 =C2=A0%% small denormalized number > + =C2=A0 =C2=A0%% 4.94065645841246544177e-324 > + =C2=A0 =C2=A0<> =3D <<0,0,0,0,0,0,0,1>>, > + =C2=A0 =C2=A0?assertEqual({0.5, -1073}, frexp(SmallDenorm)), > + =C2=A0 =C2=A0%% large denormalized number > + =C2=A0 =C2=A0%% 2.22507385850720088902e-308 > + =C2=A0 =C2=A0<> =3D <<0,15,255,255,255,255,255,255>>, > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 {0.99999999999999978, -1022}, > + =C2=A0 =C2=A0 =C2=A0 frexp(BigDenorm)), > + =C2=A0 =C2=A0%% small normalized number > + =C2=A0 =C2=A0%% 2.22507385850720138309e-308 > + =C2=A0 =C2=A0<> =3D <<0,16,0,0,0,0,0,0>>, > + =C2=A0 =C2=A0?assertEqual({0.5, -1021}, frexp(SmallNorm)), > + =C2=A0 =C2=A0%% large normalized number > + =C2=A0 =C2=A0%% 1.79769313486231570815e+308 > + =C2=A0 =C2=A0<> =3D <<127,239,255,255,255,255,255,255>= >, > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{0.99999999999999989, 1024}, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0frexp(LargeNorm)), > + =C2=A0 =C2=A0%% issue #10 - mochinum:frexp(math:pow(2, -1074)). > + =C2=A0 =C2=A0?assertEqual( > + =C2=A0 =C2=A0 =C2=A0 {0.5, -1073}, > + =C2=A0 =C2=A0 =C2=A0 frexp(math:pow(2, -1074))), > + =C2=A0 =C2=A0ok. > + > +-endif. > > Added: couchdb/trunk/src/ejson/yajl/yajl.c > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/yajl/yajl.c?rev= =3D1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/yajl/yajl.c (added) > +++ couchdb/trunk/src/ejson/yajl/yajl.c Tue Apr =C2=A05 09:42:41 2011 > @@ -0,0 +1,159 @@ > +/* > + * Copyright 2010, Lloyd Hilaiel. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions ar= e > + * met: > + * > + * =C2=A01. Redistributions of source code must retain the above copyrig= ht > + * =C2=A0 =C2=A0 notice, this list of conditions and the following discl= aimer. > + * > + * =C2=A02. Redistributions in binary form must reproduce the above copy= right > + * =C2=A0 =C2=A0 notice, this list of conditions and the following discl= aimer in > + * =C2=A0 =C2=A0 the documentation and/or other materials provided with = the > + * =C2=A0 =C2=A0 distribution. > + * > + * =C2=A03. Neither the name of Lloyd Hilaiel nor the names of its > + * =C2=A0 =C2=A0 contributors may be used to endorse or promote products= derived > + * =C2=A0 =C2=A0 from this software without specific prior written permi= ssion. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR > + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED > + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AR= E > + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, > + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES > + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR > + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING > + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#include "yajl_parse.h" > +#include "yajl_lex.h" > +#include "yajl_parser.h" > +#include "yajl_alloc.h" > + > +#include > +#include > +#include > + > +const char * > +yajl_status_to_string(yajl_status stat) > +{ > + =C2=A0 =C2=A0const char * statStr =3D "unknown"; > + =C2=A0 =C2=A0switch (stat) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case yajl_status_ok: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0statStr =3D "ok, no error"; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case yajl_status_client_canceled: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0statStr =3D "client canceled p= arse"; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case yajl_status_insufficient_data: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0statStr =3D "eof was met befor= e the parse could complete"; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case yajl_status_error: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0statStr =3D "parse error"; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0return statStr; > +} > + > +yajl_handle > +yajl_alloc(const yajl_callbacks * callbacks, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 const yajl_parser_config * config, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 const yajl_alloc_funcs * afs, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void * ctx) > +{ > + =C2=A0 =C2=A0unsigned int allowComments =3D 0; > + =C2=A0 =C2=A0unsigned int validateUTF8 =3D 0; > + =C2=A0 =C2=A0yajl_handle hand =3D NULL; > + =C2=A0 =C2=A0yajl_alloc_funcs afsBuffer; > + > + =C2=A0 =C2=A0/* first order of business is to set up memory allocation = routines */ > + =C2=A0 =C2=A0if (afs !=3D NULL) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (afs->malloc =3D=3D NULL || afs->realloc = =3D=3D NULL || afs->free =3D=3D NULL) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return NULL; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0yajl_set_default_alloc_funcs(&afsBuffer); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0afs =3D &afsBuffer; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0hand =3D (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_h= andle_t)); > + > + =C2=A0 =C2=A0/* copy in pointers to allocation routines */ > + =C2=A0 =C2=A0memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_= alloc_funcs)); > + > + =C2=A0 =C2=A0if (config !=3D NULL) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0allowComments =3D config->allowComments; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0validateUTF8 =3D config->checkUTF8; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0hand->callbacks =3D callbacks; > + =C2=A0 =C2=A0hand->ctx =3D ctx; > + =C2=A0 =C2=A0hand->lexer =3D yajl_lex_alloc(&(hand->alloc), allowCommen= ts, validateUTF8); > + =C2=A0 =C2=A0hand->bytesConsumed =3D 0; > + =C2=A0 =C2=A0hand->decodeBuf =3D yajl_buf_alloc(&(hand->alloc)); > + =C2=A0 =C2=A0yajl_bs_init(hand->stateStack, &(hand->alloc)); > + > + =C2=A0 =C2=A0yajl_bs_push(hand->stateStack, yajl_state_start); > + > + =C2=A0 =C2=A0return hand; > +} > + > +void > +yajl_free(yajl_handle handle) > +{ > + =C2=A0 =C2=A0yajl_bs_free(handle->stateStack); > + =C2=A0 =C2=A0yajl_buf_free(handle->decodeBuf); > + =C2=A0 =C2=A0yajl_lex_free(handle->lexer); > + =C2=A0 =C2=A0YA_FREE(&(handle->alloc), handle); > +} > + > +yajl_status > +yajl_parse(yajl_handle hand, const unsigned char * jsonText, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned int jsonTextLen) > +{ > + =C2=A0 =C2=A0yajl_status status; > + =C2=A0 =C2=A0status =3D yajl_do_parse(hand, jsonText, jsonTextLen); > + =C2=A0 =C2=A0return status; > +} > + > +yajl_status > +yajl_parse_complete(yajl_handle hand) > +{ > + =C2=A0 =C2=A0/* The particular case we want to handle is a trailing num= ber. > + =C2=A0 =C2=A0 * Further input consisting of digits could cause our inte= rpretation > + =C2=A0 =C2=A0 * of the number to change (buffered "1" but "2" comes in)= . > + =C2=A0 =C2=A0 * A very simple approach to this is to inject whitespace = to terminate > + =C2=A0 =C2=A0 * any number in the lex buffer. > + =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0return yajl_parse(hand, (const unsigned char *)" ", 1); > +} > + > +unsigned char * > +yajl_get_error(yajl_handle hand, int verbose, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 const unsigned char * = jsonText, unsigned int jsonTextLen) > +{ > + =C2=A0 =C2=A0return yajl_render_error_string(hand, jsonText, jsonTextLe= n, verbose); > +} > + > +unsigned int > +yajl_get_bytes_consumed(yajl_handle hand) > +{ > + =C2=A0 =C2=A0if (!hand) return 0; > + =C2=A0 =C2=A0else return hand->bytesConsumed; > +} > + > + > +void > +yajl_free_error(yajl_handle hand, unsigned char * str) > +{ > + =C2=A0 =C2=A0/* use memory allocation functions if set */ > + =C2=A0 =C2=A0YA_FREE(&(hand->alloc), str); > +} > + > +/* XXX: add utility routines to parse from file */ > > Added: couchdb/trunk/src/ejson/yajl/yajl_alloc.c > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/yajl/yajl_alloc= .c?rev=3D1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/yajl/yajl_alloc.c (added) > +++ couchdb/trunk/src/ejson/yajl/yajl_alloc.c Tue Apr =C2=A05 09:42:41 20= 11 > @@ -0,0 +1,65 @@ > +/* > + * Copyright 2010, Lloyd Hilaiel. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions ar= e > + * met: > + * > + * =C2=A01. Redistributions of source code must retain the above copyrig= ht > + * =C2=A0 =C2=A0 notice, this list of conditions and the following discl= aimer. > + * > + * =C2=A02. Redistributions in binary form must reproduce the above copy= right > + * =C2=A0 =C2=A0 notice, this list of conditions and the following discl= aimer in > + * =C2=A0 =C2=A0 the documentation and/or other materials provided with = the > + * =C2=A0 =C2=A0 distribution. > + * > + * =C2=A03. Neither the name of Lloyd Hilaiel nor the names of its > + * =C2=A0 =C2=A0 contributors may be used to endorse or promote products= derived > + * =C2=A0 =C2=A0 from this software without specific prior written permi= ssion. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR > + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED > + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AR= E > + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, > + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES > + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR > + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING > + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +/** > + * \file yajl_alloc.h > + * default memory allocation routines for yajl which use malloc/realloc = and > + * free > + */ > + > +#include "yajl_alloc.h" > +#include > + > +static void * yajl_internal_malloc(void *ctx, unsigned int sz) > +{ > + =C2=A0 =C2=A0return malloc(sz); > +} > + > +static void * yajl_internal_realloc(void *ctx, void * previous, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned int sz) > +{ > + =C2=A0 =C2=A0return realloc(previous, sz); > +} > + > +static void yajl_internal_free(void *ctx, void * ptr) > +{ > + =C2=A0 =C2=A0free(ptr); > +} > + > +void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf) > +{ > + =C2=A0 =C2=A0yaf->malloc =3D yajl_internal_malloc; > + =C2=A0 =C2=A0yaf->free =3D yajl_internal_free; > + =C2=A0 =C2=A0yaf->realloc =3D yajl_internal_realloc; > + =C2=A0 =C2=A0yaf->ctx =3D NULL; > +} > + > > Added: couchdb/trunk/src/ejson/yajl/yajl_alloc.h > URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/yajl/yajl_alloc= .h?rev=3D1088941&view=3Dauto > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- couchdb/trunk/src/ejson/yajl/yajl_alloc.h (added) > +++ couchdb/trunk/src/ejson/yajl/yajl_alloc.h Tue Apr =C2=A05 09:42:41 20= 11 > @@ -0,0 +1,50 @@ > +/* > + * Copyright 2010, Lloyd Hilaiel. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions ar= e > + * met: > + * > + * =C2=A01. Redistributions of source code must retain the above copyrig= ht > + * =C2=A0 =C2=A0 notice, this list of conditions and the following discl= aimer. > + * > + * =C2=A02. Redistributions in binary form must reproduce the above copy= right > + * =C2=A0 =C2=A0 notice, this list of conditions and the following discl= aimer in > + * =C2=A0 =C2=A0 the documentation and/or other materials provided with = the > + * =C2=A0 =C2=A0 distribution. > + * > + * =C2=A03. Neither the name of Lloyd Hilaiel nor the names of its > + * =C2=A0 =C2=A0 contributors may be used to endorse or promote products= derived > + * =C2=A0 =C2=A0 from this software without specific prior written permi= ssion. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR > + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED > + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AR= E > + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, > + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES > + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR > + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING > + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +/** > + * \file yajl_alloc.h > + * default memory allocation routines for yajl which use malloc/realloc = and > + * free > + */ > + > +#ifndef __YAJL_ALLOC_H__ > +#define __YAJL_ALLOC_H__ > + > +#include "yajl_common.h" > + > +#define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz)) > +#define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr)) > +#define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz)) > + > +void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf); > + > +#endif > > > --=20 Filipe David Manana, fdmanana@gmail.com, fdmanana@apache.org "Reasonable men adapt themselves to the world. =C2=A0Unreasonable men adapt the world to themselves. =C2=A0That's why all progress depends on unreasonable men."